home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / sys / amiga / wb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-03  |  83.7 KB  |  3,853 lines

  1. /*    SCCS Id: @(#)wb.c     2.1   93/01/08              */
  2. /*    Copyright (c) Kenneth Lorber, Bethesda Maryland, 1991      */
  3. /*    Copyright (c) Gregg Wonderly, Naperville IL, 1992, 1993      */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. /* Friendly Intuition interface for NetHack 3.1 on the Amiga */
  7.  
  8. #ifdef AZTEC_C
  9. /* Aztec doesn't recognize __chip syntax */
  10. # define __chip
  11. #endif
  12.  
  13. #include "incl:patchlevel.h"
  14.  
  15. #include "Amiga:wbdefs.h"        /* Miscellany information */
  16. #ifdef  INTUI_NEW_LOOK
  17. #define NewWindow   ExtNewWindow
  18. #define NewScreen   ExtNewScreen
  19. #endif
  20. #include "Amiga:wbstruct.h"
  21. #include "Amiga:wbprotos.h"
  22.  
  23. #include "Amiga:wbdata.c"        /* All structures and global data */
  24. #include "Amiga:wbwin.c"        /* Has static definitions */
  25.  
  26. #define C_GREY  0
  27. #define C_BLACK 1
  28. #define C_WHITE 2
  29. #define C_BLUE  3
  30.  
  31. #ifndef __SASC_60
  32. extern char *sys_errlist[];
  33. #endif
  34. extern int errno;
  35.  
  36. char pubscreen[ 80 ] = { "HackWB" };
  37. char mytitle[ 80 ];
  38.  
  39. #ifdef  INTUI_NEW_LOOK
  40. int scrlocked = 0;
  41. UWORD scrnpens[] = { 0xffff };
  42.  
  43. struct TagItem scrntags[] =
  44. {
  45.     (Tag)SA_Pens, (ULONG)scrnpens,
  46.     TAG_DONE, 0,
  47.     TAG_DONE, 0,
  48.     TAG_DONE, 0,
  49.     TAG_DONE, 0,
  50.     TAG_DONE, 0,
  51.     TAG_DONE, 0,
  52.     TAG_DONE, 0,
  53. };
  54. #endif
  55.  
  56. #define SPLIT            /* use splitter, if available */
  57. #ifdef SPLIT
  58. int running_split=0;        /* if 0, using normal LoadSeg/UnLoadSeg */
  59. #endif
  60.  
  61. #ifdef AZTEC_C
  62. extern char *strdup(char *);
  63. #endif
  64.  
  65. #ifndef max
  66. # define max(a, b) ((a) > (b) ? (a) : (b))
  67. #endif
  68. #ifndef min
  69. # define min(x,y) ((x) < (y) ? (x) : (y))
  70. #endif
  71.  
  72. void diskobj_filter(struct DiskObject *);
  73. static void UpdateInfoWin( struct Window *cwin );
  74. BPTR s_LoadSeg(char *);
  75. void s_UnLoadSeg(void);
  76.  
  77. main( argc, argv )
  78.     int argc;
  79.     struct WBStartup *argv;
  80. {
  81.     long mask, rmask;
  82.     struct WBStartup *wbs;
  83.     struct WBArg *wba;
  84.     GPTR gptr;
  85.     struct IntuiMessage *imsg;
  86.     struct IntuiMessage mimsg;
  87.     int i;
  88.  
  89.     /* Initialize and load libraries. */
  90.     InitWB( argc, argv );
  91.  
  92.     /* open window, build menus */
  93.     SetupWB( );
  94.  
  95.     errmsg( NO_FLASH, "Welcome to NetHack Version %d.%d.%d!",
  96.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
  97.  
  98.     CopyRight( );
  99.  
  100.     ReadConfig( );
  101.  
  102.     /* Initially, no game selected so disable menu items */
  103.  
  104.     ChgGameItems( &MenuList1, 0 );
  105.  
  106.     MapGadgets( R_DISK, 1 ); /* Display the icons */
  107.  
  108.     /* Wait till user quits */
  109.  
  110.     while( !quit )
  111.     {
  112.     /* Wait for a message */
  113.  
  114.     mask = ( 1L << dosport->mp_SigBit ) ;
  115.     if( wbopen )
  116.         mask |= ( 1L << win->UserPort->mp_SigBit );
  117.  
  118.     rmask = Wait( mask );
  119.  
  120.     /* Process the messages on the port unless the workbench is
  121.      * shutdown by a request to play a game.
  122.      */
  123.  
  124.     while( wbopen && ( imsg = ( struct IntuiMessage * )
  125.         GetMsg( win->UserPort ) ) )
  126.     {
  127.         /* Copy the message.  This does not guarantee that all
  128.          * fields will still be valid, but appears to work
  129.          * here.  Note that we have to reply to the message
  130.          * before the workbench window is closed.
  131.          */
  132.  
  133.         mimsg = *imsg;
  134.         ReplyMsg( (struct Message *)imsg );
  135.  
  136.         switch( mimsg.Class )
  137.         {
  138.         case NEWSIZE:
  139.         ((struct Border *) Message.GadgetRender)->XY[2] =
  140.             win->Width - win->BorderLeft -
  141.             win->BorderRight - 1;
  142.         RefreshGList( &Message, win, NULL, 1 );
  143.         MapGadgets( R_SCROLL, 1 ); /* redisplay the icons */
  144. #ifdef  INTUI_NEW_LOOK
  145.         if( IntuitionBase->LibNode.lib_Version >= 37 )
  146.             RefreshWindowFrame( win );
  147. #endif
  148.         break;
  149.  
  150.         case MENUPICK:
  151.         if( errup > 0 )
  152.         {
  153.             errmsg( NO_FLASH, "" );
  154.             errup = -1;
  155.         }
  156.         do_menu( &MenuList1, mimsg.Code );
  157.         flushIDCMP( win->UserPort );
  158.         break;
  159.  
  160.         case RAWKEY:
  161.         if( mimsg.Code == 0x5f )
  162.         {
  163.             if( errup > 0 )
  164.             {
  165.             errmsg( NO_FLASH, "" );
  166.             errup = -1;
  167.             }
  168.  
  169.             /* Pick the correct help message */
  170.  
  171.             if( lastgaddown == NULL )
  172.             {
  173.             text_requester( &Help1_NewWindowStructure7,
  174.                 &Help1_IntuiTextList7 );
  175.             }
  176.             else
  177.             {
  178.             text_requester( &Help2_NewWindowStructure8,
  179.                 &Help2_IntuiTextList8 );
  180.             }
  181.         }
  182.         flushIDCMP( win->UserPort );
  183.         break;
  184.  
  185.         case CLOSEWINDOW:
  186.         if( Ask( "Ready to Quit?" ) )
  187.             do_closewindow( );
  188.         break;
  189.  
  190.         case GADGETDOWN:
  191.         if( errup > 0 )
  192.         {
  193.             errmsg( NO_FLASH, "" );
  194.             errup = -1;
  195.         }
  196.         do_gadgetdown( &mimsg );
  197.         break;
  198.  
  199.         case GADGETUP:
  200.         do_gadgetup( &mimsg );
  201.         break;
  202.  
  203.         case DISKINSERTED:
  204.         if( errup > 0 )
  205.         {
  206.             errmsg( NO_FLASH, "" );
  207.             errup = -1;
  208.         }
  209.         MapGadgets( R_DISK, 1 );
  210.         break;
  211.  
  212.         case MOUSEBUTTONS:
  213.         if( errup > 0 )
  214.         {
  215.             errmsg( NO_FLASH, "" );
  216.             errup = -1;
  217.         }
  218.         do_buttons( &mimsg );
  219.         flushIDCMP( win->UserPort );
  220.         break;
  221.         }
  222.     }
  223.     if( errup == -1 )
  224.         errup = 0;
  225.  
  226.     if( rmask & ( 1L << dosport->mp_SigBit ) )
  227.     {
  228.         /* Get process termination messages */
  229.  
  230.         while( wbs = (struct WBStartup *) GetMsg( dosport ) )
  231.         {
  232.         /* Find the game that has terminated */
  233.  
  234.         for( gptr = gamehead; gptr && gptr->seglist != wbs->sm_Segment;)
  235.             gptr = gptr->next;
  236.  
  237.         /* Make sure it is there */
  238.  
  239.         if( gptr )
  240.         {
  241. #ifdef SPLIT
  242.             if(!running_split)
  243. #endif
  244.             {
  245.             /* Unload the code */
  246.             UnLoadSeg( wbs->sm_Segment );
  247.             }
  248.  
  249.             /* Free the startup message resources */
  250.             wba = (struct WBArg *)
  251.             ((long)wbs + sizeof( struct WBStartup ));
  252.             for( i = 0; i < wbs->sm_NumArgs; ++i )
  253.             {
  254.             FreeMem( wba[i].wa_Name,
  255.                 strlen( wba[i].wa_Name ) + 1 );
  256.             UnLock( wba[i].wa_Lock );
  257.             }
  258.             FreeMem( wbs, wbs->sm_Message.mn_Length );
  259.             wbs = NULL;
  260.  
  261.             /* Say the game has completed */
  262.  
  263.             gptr->prc = NULL;
  264.             gptr->active = 0;
  265.             active_count--;
  266.         }
  267.         }
  268.  
  269.         /* If the workbench was closed, open it back up */
  270.  
  271.         if( !wbopen )
  272.         SetupWB( );
  273.  
  274.         /* Reload to clear any deleted games */
  275.  
  276.         MapGadgets( R_DISK, 1 );
  277.     }
  278.     }
  279.     cleanup( 0 );
  280. }
  281.  
  282. void
  283. flushIDCMP( port )
  284.     struct MsgPort *port;
  285. {
  286.     struct Message *msg;
  287.  
  288.     while( msg = GetMsg( port ) )
  289.         ReplyMsg( msg );
  290.  
  291.     SetSignal( 0L, ( 1L << port->mp_SigBit ) );
  292. }
  293.  
  294. void CopyRight( )
  295. {
  296.     extern char *copyright_text[];
  297.     int line;
  298.  
  299.     SetDrMd( win->RPort, JAM2 );
  300.     SetAPen( win->RPort, C_WHITE );
  301.     SetBPen( win->RPort, C_GREY );
  302.  
  303.     for(line=0;copyright_text[line];line++){
  304.     Move( win->RPort, ORIGINX+3, ORIGINY + win->RPort->TxBaseline +
  305.         (line*win->RPort->TxHeight));
  306.     if(copyright_text[line][0])
  307.          RPText( win->RPort, copyright_text[line]);
  308.     }
  309.  
  310.     Delay( 150 );
  311.     ClearWindow( win );
  312. }
  313.  
  314. /*
  315.  * Do the one time initialization things.
  316.  */
  317.  
  318. void
  319. InitWB( argc, wbs )
  320.     int argc;
  321.     register struct WBStartup *wbs;
  322. {
  323.     register int c, i, j;
  324.     BPTR odir;
  325.     char *s, **tools, **argv;
  326.     register struct DiskObject *dobj;
  327.     register struct WBArg *wba;
  328.  
  329.     /* Open Libraries */
  330.     GfxBase= (struct GfxBase *) OldOpenLibrary("graphics.library");
  331.     IconBase= OldOpenLibrary("icon.library");
  332.     DiskfontBase= (struct DiskfontBase *)OldOpenLibrary("diskfont.library");
  333.     IntuitionBase= (struct IntuitionBase *)OldOpenLibrary("intuition.library");
  334.  
  335.     if(!GfxBase || !IconBase || !DiskfontBase || !IntuitionBase)
  336.     {
  337.     error("library open failed");
  338.     cleanup( 1 );
  339.     }
  340.  
  341.     /* Get Port for replied WBStartup messages */
  342.  
  343.     if( ( dosport = CreatePort( NULL, 0 ) ) == NULL )
  344.     {
  345.     error("failed to create dosport" );
  346.     cleanup( 1 );
  347.     }
  348.  
  349.     /* If started from CLI */
  350.     if( argc != 0 )
  351.     {
  352.     argv = (char **)wbs;
  353.     for( i = 1; i < argc; ++i )
  354.     {
  355.         if( argv[i][0] == '?' )goto usage;
  356.         if( argv[i][0] != '-' )
  357.         break;
  358.         for( j = 1; c = argv[i][j]; ++j )
  359.         {
  360.         switch( c )
  361.         {
  362.         case 'm':   /* Close screen and window during game to
  363.                  * save memory  */
  364.             shutdown++;
  365.             break;
  366.  
  367.         case 'c':       /* Configuration to load */
  368.             if( i + 1 < argc && argv[i][j+1] == 0 )
  369.             {
  370.             strcpy( StrConf, argv[ ++i ] );
  371.             goto nextargv;
  372.             }
  373.             else
  374.             {
  375.             fprintf( stderr,
  376.                 "%s: missing config name after -c\n",
  377.                 argv[ 0 ] );
  378.             cleanup( 1 );
  379.             }
  380.             break;
  381.  
  382.         case 'N':       /* Public screen name */
  383.             if( i + 1 < argc && argv[i][j+1] == 0 )
  384.             {
  385.             strcpy( pubscreen, argv[ ++i ] );
  386.             goto nextargv;
  387.             }
  388.             else
  389.             {
  390.             fprintf( stderr,
  391.                 "%s: missing screen name after -N\n",
  392.                 argv[ 0 ] );
  393.             cleanup( 1 );
  394.             }
  395.             break;
  396.  
  397.         case 'f':       /* Default game "player" */
  398.             if( i + 1 < argc && argv[i][j+1] == 0 )
  399.             {
  400.             strcpy( defgname, argv[ ++i ] );
  401.             goto nextargv;
  402.             }
  403.             else
  404.             {
  405.             fprintf( stderr,
  406.                 "%s: missing name after -f\n",
  407.                 argv[ 0 ] );
  408.                 cleanup( 1 );
  409.             }
  410.             break;
  411.         default:
  412.             fprintf( stderr, "%s: invalid option %c\n",
  413.             argv[0], c );
  414. usage:
  415.             fprintf( stderr,
  416. "usage: %s [-m] [-f .def filename] [-c config filename] [ -N screen]\n",
  417.             argv[ 0 ] );
  418.             cleanup( 1 );
  419.         }
  420.         }
  421. nextargv:;
  422.     }
  423.     }
  424.     else
  425.     {
  426.     /* Process icon's ToolTypes */
  427.  
  428.     wba = wbs->sm_ArgList;
  429.     odir = CurrentDir( wba->wa_Lock );
  430.     if( dobj = GetDiskObject( wba->wa_Name ) )
  431.     {
  432.         tools = (char **) dobj->do_ToolTypes;
  433.  
  434.         if( s = FindToolType( tools, "OPTIONS" ) )
  435.         {
  436.         /* OPTIONS=SHUTDOWN will cause the screen to be closed
  437.          * when a game is started
  438.          */
  439.         if( MatchToolValue( s, "SHUTDOWN" ) )
  440.             ++shutdown;
  441.         }
  442.  
  443.         /* A different configuration file name */
  444.  
  445.         if( s = FindToolType( tools, "CONFIG" ) )
  446.         {
  447.         strcpy( StrConf, s );
  448.         }
  449.  
  450.         /* A different set of defaults then 'wbdefaults.def' */
  451.  
  452.         if( s = FindToolType( tools, "DEFAULT" ) )
  453.         {
  454.         strcpy( defgname, s );
  455.         }
  456.  
  457.         /* A Public screen to open onto */
  458.  
  459.         if( s = FindToolType( tools, "SCREEN" ) )
  460.         {
  461.         strcpy( pubscreen, s );
  462.         }
  463.  
  464.         FreeDiskObject( dobj );
  465.     }
  466.     if( odir )
  467.         CurrentDir( odir );
  468.     }
  469. }
  470.  
  471. /*
  472.  * Read a nethack.cnf like file and collect the configuration
  473.  * information from it.
  474.  */
  475. void ReadConfig()
  476. {
  477.     register FILE *fp;
  478.     register char *buf, *t;
  479.  
  480.     /* Use a dynamic buffer to limit stack use */
  481.  
  482.     if( ( buf = xmalloc( 1024 ) ) == NULL )
  483.     {
  484.     error( "Can't alloc space to read config file" );
  485.     cleanup( 1 );
  486.     }
  487.  
  488.     /* If the file is not there, can't load it */
  489.  
  490.     if( ( fp = fopen( StrConf, "r" ) ) == NULL )
  491.     {
  492.     errmsg( FLASH, "Can't load config file %s", StrConf );
  493.     free( buf );
  494.     return;
  495.     }
  496.  
  497.     /* Read the lines... */
  498.  
  499.     while( fgets( buf, 1024, fp ) != NULL )
  500.     {
  501.     if( *buf == '#' )
  502.         continue;
  503.  
  504.     if( ( t = strchr( buf, '\n' ) ) != NULL )
  505.         *t = 0;
  506.  
  507.     if( strnicmp( buf, "PATH=", 5 ) == 0 )
  508.     {
  509.         setoneopt( PATH_IDX, buf + 5 );
  510.     }
  511.     else if( strnicmp( buf, "PENS=", 4 ) == 0 )
  512.     {
  513.         setoneopt( PENS_IDX, buf + 5 );
  514.     }
  515.     else if( strnicmp( buf, "OPTIONS=", 8 ) == 0 )
  516.     {
  517.         setoneopt( OPTIONS_IDX, buf + 8 );
  518.     }
  519.     else if( strnicmp( buf, "HACKDIR=", 8 ) == 0 )
  520.     {
  521.         setoneopt( HACKDIR_IDX, buf + 8 );
  522.     }
  523.     else if( strnicmp( buf, "LEVELS=", 7 ) == 0 )
  524.     {
  525.         setoneopt( LEVELS_IDX, buf + 7 );
  526.     }
  527.     else if( strnicmp( buf, "SAVE=", 5 ) == 0 )
  528.     {
  529.         setoneopt( SAVE_IDX, buf + 5 );
  530.     }
  531.     else
  532.     {
  533.         /* We don't allow manipulation of the other information */
  534.     }
  535.     }
  536.     fclose( fp );
  537.     free( buf );
  538. }
  539.  
  540. /* Close the workbench screen and window */
  541.  
  542. void CloseDownWB( )
  543. {
  544.     ((struct Process *)FindTask( NULL ))->pr_WindowPtr = (APTR)oldwin;
  545.  
  546.     if( win && win->RPort->TmpRas )
  547.     {
  548.     FreeRaster( tmprasp, width, height );
  549.     }
  550.  
  551.     if( win )
  552.     SafeCloseWindow( win );
  553.  
  554. #ifdef  INTUI_NEW_LOOK
  555.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  556.     {
  557.     while( !scrlocked && CloseScreen( scrn ) == FALSE )
  558.     {
  559.         Ask("Close all vistor Windows to exit" );
  560.     }
  561.     }
  562.     else
  563. #endif
  564.     {
  565.     CloseScreen( scrn );
  566.     }
  567.     wbopen = 0;
  568. }
  569.  
  570. /* Open the workbench screen and window. */
  571.  
  572. void SetupWB( )
  573. {
  574.     int cpyrwid, i;
  575.     int txtdiff;
  576. #ifdef  INTUI_NEW_LOOK
  577.     int pubopen = 0;
  578. #endif
  579.     static int once = 0;
  580.  
  581.     scrlocked = 0;
  582. #ifdef  INTUI_NEW_LOOK
  583.     NewScreenStructure.Extension = scrntags;
  584.     NewScreenStructure.Type |= NS_EXTENDED;
  585. #endif
  586.  
  587.     NewScreenStructure.Width = GfxBase->NormalDisplayColumns;
  588.     NewScreenStructure.Height = GfxBase->NormalDisplayRows;
  589.  
  590.     {
  591.     static char dt[40];
  592.     sprintf(dt,"WorkBench for V%d.%d.%d of NetHack",
  593.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
  594.     NewScreenStructure.DefaultTitle = dt;
  595.     }
  596.  
  597. #ifdef  INTUI_NEW_LOOK
  598.     if( IntuitionBase->LibNode.lib_Version < 37 )
  599.     {
  600. #endif
  601.     if( ( scrn = OpenScreen( (void *)
  602.         &NewScreenStructure ) ) == NULL )
  603.     {
  604.         error( "Can't create screen" );
  605.         cleanup( 1 );
  606.     }
  607.  
  608.     /* Only set the pens on the screen we open */
  609.     LoadRGB4( &scrn->ViewPort, Palette, PaletteColorCount );
  610. #ifdef  INTUI_NEW_LOOK
  611.     }
  612.     else
  613.     {
  614.     /* No tags beyond here yet */
  615.     scrntags[1].ti_Tag = TAG_DONE;
  616.  
  617.     if( *pubscreen != 0 )
  618.     {
  619.         if( ( scrn = LockPubScreen( pubscreen ) ) == 0 )
  620.         {
  621.         /* Now add our pub screen name */
  622.         scrntags[1].ti_Tag = SA_PubName;
  623.         scrntags[1].ti_Data = (ULONG) pubscreen;
  624.         scrntags[2].ti_Tag = TAG_DONE;
  625.  
  626.         /* Get the default pub screen's size */
  627.         scrn = LockPubScreen( NULL );
  628.         NewScreenStructure.Height = scrn->Height;
  629.         NewScreenStructure.Width = scrn->Width;
  630.         UnlockPubScreen( NULL, scrn );
  631.  
  632.         /* Request LACE if it looks laced.  For 2.1/3.0, we will get
  633.          * promoted to the users choice of modes (if promotion is alloed)
  634.          * which is best to avoid extra coding involving copying of the
  635.          * viewport modes etc.
  636.          */
  637.         if( NewScreenStructure.Height > 300 )
  638.             NewScreenStructure.ViewModes |= LACE;
  639.  
  640.         if( ( scrn = OpenScreen( (void *)
  641.             &NewScreenStructure ) ) == NULL )
  642.         {
  643.             NewScreenStructure.Height = GfxBase->NormalDisplayRows;
  644.             NewScreenStructure.Width = GfxBase->NormalDisplayColumns;
  645.             if( ( scrn = OpenScreen( (void *)
  646.             &NewScreenStructure ) ) == NULL )
  647.             {
  648.             error( "Can't create screen" );
  649.             cleanup( 1 );
  650.             }
  651.         }
  652.         pubopen = 1;
  653.         scrlocked = 0;
  654.         }
  655.         else
  656.         {
  657.         pubopen = 0;
  658.         scrlocked = 1;
  659.         }
  660.     }
  661.     else
  662.     {
  663.         if( ( scrn = LockPubScreen( NULL ) ) == 0 )
  664.         {
  665.         error( "Can't lock Workbench screen" );
  666.         cleanup( 1 );
  667.         }
  668.         scrlocked = 1;
  669.     }
  670.     }
  671. #endif
  672.  
  673.     cpyrwid = 0;
  674.     for( i = 0; copyright_text[i]; ++i )
  675.     cpyrwid = max(cpyrwid, strlen( copyright_text[i] ) );
  676.  
  677.     /* 28 is magic for the width of the sizing gadget under 2.04 and
  678.      * later.
  679.      */
  680.     NewWindowStructure1.Width = (cpyrwid * scrn->RastPort.TxWidth) +
  681.         scrn->WBorLeft + scrn->WBorRight + 28;
  682.  
  683.     width = NewWindowStructure1.Width;
  684.  
  685.     if( NewWindowStructure1.LeftEdge + width > scrn->Width )
  686.     {
  687.     if( width > scrn->Width )
  688.     {
  689.         NewWindowStructure1.LeftEdge = 0;
  690.         NewWindowStructure1.Width = scrn->Width;
  691.     }
  692.     else
  693.     {
  694.         NewWindowStructure1.LeftEdge = (scrn->Width - width)/2;
  695.     }
  696.     }
  697.     height = NewWindowStructure1.Height;
  698.     NewWindowStructure1.Screen = scrn;
  699.  
  700.     txtdiff = scrn->RastPort.TxHeight - 8;
  701.  
  702. #ifdef  INTUI_NEW_LOOK
  703.     if( scrlocked )
  704.     sprintf( mytitle, "NetHack WB %d.%d.%d - Select a GAME or press HELP",
  705.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
  706.  
  707.     else
  708.     strcpy( mytitle, "Select a GAME or press HELP" );
  709.  
  710.     NewWindowStructure1.Title = mytitle;
  711.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  712.     {
  713.     ((struct PropInfo *)Scroll.SpecialInfo)->Flags |= PROPNEWLOOK;
  714.     }
  715. #endif
  716.  
  717.     if( !once )
  718.     {
  719.     ((struct Border *) Message.GadgetRender)->XY[2] =
  720.         NewWindowStructure1.Width +
  721.         Message.Width - Message.LeftEdge;
  722.     Message.TopEdge = scrn->RastPort.TxHeight + scrn->WBorTop + 1;
  723.     Message.Height = scrn->RastPort.TxHeight + 3;
  724.         ((struct Border *) Message.GadgetRender)->XY[1] =
  725.         (((struct Border *) Message.GadgetRender)->XY[3] +=
  726.         scrn->RastPort.TxHeight - 6 );
  727.     }
  728.  
  729.     if( ( win = MyOpenWindow( &NewWindowStructure1 ) ) == NULL )
  730.     {
  731. #ifdef  INTUI_NEW_LOOK
  732.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  733.     {
  734.         if( scrlocked )
  735.         UnlockPubScreen( NULL, scrn );
  736.     }
  737. #endif
  738.     error( "Can't create window" );
  739.     cleanup( 1 );
  740.     }
  741. #ifdef  INTUI_NEW_LOOK
  742.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  743.     {
  744.     /* If we did not create this screen, unlock it.
  745.      * otherwise, advertise it for other applications
  746.      * to use.
  747.      */
  748.     if( scrlocked )
  749.         UnlockPubScreen( NULL, scrn );
  750.     else if( pubopen )
  751.         PubScreenStatus( scrn, 0 );
  752.     }
  753. #endif
  754.  
  755.     ((struct Border *) Message.GadgetRender)->XY[2] =
  756.         win->Width - win->BorderLeft -
  757.         win->BorderRight - 1;
  758.  
  759.     RefreshGList( &Message, win, NULL, 1 );
  760. #ifdef  INTUI_NEW_LOOK
  761.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  762.     RefreshWindowFrame( win );
  763. #endif
  764.  
  765.     oldwin = (struct Window *)((struct Process *)FindTask( NULL ))->pr_WindowPtr;
  766.     ((struct Process *)FindTask( NULL ))->pr_WindowPtr = (APTR)win;
  767.  
  768.     if( ( tmprasp = (void *) AllocRaster( width, height ) ) == NULL )
  769.     {
  770.     win->RPort->TmpRas = NULL;
  771.     fprintf( stderr, "No Space for raster %d x %d\n", height, width );
  772.     cleanup( 1 );
  773.     }
  774.  
  775.     InitTmpRas( &tmpras, tmprasp, RASSIZE( width, height ) );
  776.  
  777.     win->RPort->TmpRas = &tmpras;
  778.  
  779.     SetUpMenus( &MenuList1, scrn );
  780.     SetMenuStrip( win, &MenuList1 );
  781.     wbopen = 1;
  782.     once = 1;
  783. }
  784.  
  785. /* Map the gadgets onto the screen at the correct location */
  786.  
  787. void MapGadgets( reason, update )
  788.     int reason;
  789.     int update;
  790. {
  791.     GPTR gptr;
  792.  
  793.     /* Make sure that any down gadget is popped back up */
  794.  
  795.     if( lastgaddown )
  796.     SetGadgetUP( &lastgaddown->dobj->do_Gadget );
  797.     lastgaddown = NULL;
  798.  
  799.     /* Grey Menu Items, no Game icon will be selected */
  800.  
  801.     ChgGameItems( &MenuList1, 0 );
  802.  
  803.     /* Remove them first */
  804.  
  805.     for( gptr = windowgads; gptr; gptr = gptr->nextwgad )
  806.     {
  807.     RemoveGadget( win, &gptr->dobj->do_Gadget );
  808.     }
  809.     windowgads = NULL;
  810.  
  811.     /* Remove any non-existant games */
  812.  
  813.     ClearDelGames( );
  814.  
  815.     /* If disk changed, reload existing icons */
  816.  
  817.     if( reason == R_DISK )
  818.     {
  819.     LoadIcons( );
  820.     }
  821.  
  822.     /* Always move back to home unless we were scrolling */
  823.  
  824.     if( reason != R_SCROLL )
  825.     {
  826.     curcol = 0;
  827.     }
  828.  
  829.     /* Calculate locations and display gadgets */
  830.  
  831.     CalcLocs( update );
  832. }
  833.  
  834. void ClearWindow( win )
  835.     struct Window *win;
  836. {
  837.     /* Clear the old gadgets from the window */
  838.  
  839.     SetAPen( win->RPort, C_GREY );
  840.     SetOPen( win->RPort, C_GREY );
  841.     SetDrPt( win->RPort, 0xffff );
  842.     SetDrMd( win->RPort, JAM2 );
  843.  
  844.     RectFill( win->RPort, ORIGINX, ORIGINY, CORNERX-1, CORNERY-1 );
  845. }
  846.  
  847. /* Calculate the place for and attach the gadgets to the window */
  848.  
  849. void
  850. CalcLocs( update )
  851.     int update;
  852. {
  853.     register GPTR gptr;
  854.     register USHORT ox, oy, cx, cy;
  855.     int gadid = GADNEWGAME;
  856.     int addx = 0, sizex, sizey;
  857.  
  858.     cols = vcols = 0;
  859.     scol = -1;
  860.  
  861.     /* Upper left corner of window */
  862.  
  863.     ox = ORIGINX;
  864.     oy = ORIGINY;
  865.  
  866.     /* Lower right corner of window */
  867.  
  868.     cx = CORNERX;
  869.  
  870.     /* Account for text labels at the bottom by pulling the bottom up. */
  871.     cy = CORNERY - win->RPort->TxHeight - 3;
  872.  
  873.     ClearWindow( win );
  874.  
  875.     /* Map the current list */
  876.  
  877.     for( gptr = gamehead; gptr; gptr = gptr->next )
  878.     {
  879.     /* If not to the horizontal offset yet, don't display */
  880.  
  881.     sizex = GADWIDTH( &gptr->dobj->do_Gadget );
  882.     sizey = gptr->dobj->do_Gadget.Height;
  883.     addx = max( sizex, addx );
  884.  
  885.     /* If the current column comes before the visible column... */
  886.     if( cols < curcol )
  887.     {
  888.         oy += sizey + GADINCY + 3;
  889.         if( gptr->next )
  890.         {
  891.         if( oy + gptr->next->dobj->do_Gadget.Height + 3 >= cy )
  892.         {
  893.             cols++;
  894.             ox += addx + GADINCX;
  895.             if( GADWIDTH( &gptr->next->dobj->do_Gadget ) >
  896.             gptr->next->dobj->do_Gadget.Width )
  897.             {
  898.             ox += ( GADWIDTH( &gptr->next->dobj->do_Gadget ) -
  899.             gptr->next->dobj->do_Gadget.Width ) / 2 + 1;
  900.             }
  901.             oy = ORIGINY;
  902.             addx = 0;
  903.         }
  904.         }
  905.         continue;
  906.     }
  907.  
  908.     if( scol == -1 )
  909.     {
  910.         ox = ORIGINX;
  911.         scol = cols;
  912.     }
  913.  
  914.     /* If visible, draw it */
  915.  
  916.     if( ox + sizex + GADINCX < cx )
  917.     {
  918.         /* Link to mapped gadgets list */
  919.  
  920.         gptr->nextwgad = windowgads;
  921.         windowgads = gptr;
  922.  
  923.         /* Set screen locations, if text is longer, scoot the
  924.          * gadget over to make room for it.
  925.          */
  926.  
  927.         if( GADWIDTH( &gptr->dobj->do_Gadget ) >
  928.             gptr->dobj->do_Gadget.Width )
  929.         {
  930.         gptr->dobj->do_Gadget.LeftEdge = ox +
  931.             ( GADWIDTH( &gptr->dobj->do_Gadget ) -
  932.             gptr->dobj->do_Gadget.Width ) / 2 + 1;
  933.         }
  934.         else
  935.         gptr->dobj->do_Gadget.LeftEdge = ox;
  936.         addx = max( addx, GADWIDTH( &gptr->dobj->do_Gadget) );
  937.         gptr->dobj->do_Gadget.TopEdge = oy;
  938.         gptr->dobj->do_Gadget.GadgetID = gadid++;
  939.  
  940.         AddGadget( win, &gptr->dobj->do_Gadget, 0 );
  941.     }
  942.  
  943.     /* Stack vertically first, then horizontally */
  944.  
  945.     if( gptr->next )
  946.     {
  947.         oy += sizey + GADINCY + 3;
  948.         if( oy + gptr->next->dobj->do_Gadget.Height + 3 >= cy )
  949.         {
  950.         ox += addx + GADINCX;
  951.         cols++;
  952.         if( ox + GADWIDTH( &gptr->next->dobj->do_Gadget) < cx )
  953.             vcols++;
  954.         addx = 0;
  955.         oy = ORIGINY;
  956.         }
  957.     }
  958.     }
  959.  
  960.     /* Display all of the gadgets */
  961.  
  962.     RefreshGList( win->FirstGadget, win, NULL, -1 );
  963.  
  964.     /* Set up the slider if forcing a new position, otherwise
  965.      * the slider was probably moved and its position should be
  966.      * left where the user put it instead of jerking it around
  967.      */
  968.     if( update )
  969.     UpdatePropGad( win, &Scroll, vcols+1, cols+1, scol );
  970. }
  971.  
  972. /* Open the indicated window and place the IntuiText list passed in that
  973.  * window.  Then wait for the OKAY gadget to be clicked on.
  974.  */
  975. void text_requester( newwin, tlist )
  976.     register struct NewWindow *newwin;
  977.     struct IntuiText *tlist;
  978. {
  979.     register struct Window *win;
  980.     register struct IntuiMessage *imsg;
  981.     register struct Gadget *gd;
  982.     int done = 0;
  983.     int i;
  984.     long class;
  985.     struct NewWindow **aonce;
  986.     static struct NewWindow *once[ 6+1 ];
  987.     int lines[ 10 ], lcnt = 0, avone = -1;
  988.     register int txtdiff = scrn->RastPort.TxHeight - 8;
  989.  
  990.     newwin->Screen = scrn;
  991.  
  992.     for( i = 0; i < 6; ++i )
  993.     {
  994.     if( newwin == once[i] )
  995.         break;
  996.     if( once[i] == 0 && avone == -1 )
  997.         avone = i;
  998.     }
  999.     aonce = &once[avone];
  1000.  
  1001.     /* If spacing not correct, fix it up now */
  1002.     if( *aonce == NULL )
  1003.     {
  1004.     register struct IntuiText *ip = tlist;
  1005.     for( ; ip; ip = ip->NextText )
  1006.     {
  1007.         if( lcnt == 0 )
  1008.         lines[ lcnt++ ] = ip->TopEdge;
  1009.         else
  1010.         {
  1011.         register found = 0;
  1012.         for( i = 0; i < lcnt; ++i )
  1013.         {
  1014.             if( lines[ i ] > ip->TopEdge )
  1015.             break;
  1016.             if( lines[ i ] == ip->TopEdge )
  1017.             {
  1018.             found = 1;
  1019.             break;
  1020.             }
  1021.         }
  1022.  
  1023.         if( !found )
  1024.         {
  1025.             if( i < lcnt )
  1026.             {
  1027.             int j;
  1028.             for( j = lcnt; j > i; --j )
  1029.                 lines[ j ] = lines[ j - 1 ];
  1030.             }
  1031.             lcnt++;
  1032.             lines[ i ] = ip->TopEdge;
  1033.         }
  1034.         }
  1035.     }
  1036.  
  1037.     for( ip = tlist; ip; ip = ip->NextText )
  1038.     {
  1039.         for( i = 0; i < lcnt; ++i )
  1040.         {
  1041.         if( ip->TopEdge == lines[ i ] )
  1042.         {
  1043.             ip->TopEdge += txtdiff*i;
  1044.             break;
  1045.         }
  1046.         }
  1047.     }
  1048.  
  1049.     gd = FindGadget( NULL, newwin, GADHELPOKAY );
  1050.     gd->TopEdge += (lcnt+1)*txtdiff;
  1051.     gd->Height += txtdiff;
  1052.     SetBorder( gd, -1 );
  1053.     newwin->Height += txtdiff * (lcnt+2);
  1054.     *aonce = newwin;
  1055.     }
  1056.  
  1057.     if( ( win = MyOpenWindow( newwin ) ) == NULL )
  1058.     {
  1059.     errmsg( FLASH, "Can't create window" );
  1060.     return;
  1061.     }
  1062.  
  1063.     PrintIText( win->RPort, tlist, 0, txtdiff );
  1064.  
  1065.     while( !done )
  1066.     {
  1067.     WaitPort( win->UserPort );
  1068.     while( ( imsg = (struct IntuiMessage * )
  1069.         GetMsg( win->UserPort ) ) != NULL )
  1070.     {
  1071.         class = imsg->Class;
  1072.         ReplyMsg( (struct Message *) imsg );
  1073.         switch( class )
  1074.         {
  1075.         case CLOSEWINDOW: done = 1; break;
  1076.         case VANILLAKEY: done = 1; break;
  1077.         /* Should be GADHELPOKAY */
  1078.         case GADGETUP: done = 1; break;
  1079.         }
  1080.     }
  1081.     }
  1082.     SafeCloseWindow( win );
  1083. }
  1084.  
  1085. /* Scroll through a file which is passed by name */
  1086.  
  1087. void help_requester( file )
  1088.     char *file;
  1089. {
  1090.     register struct Window *win;
  1091.     register struct IntuiMessage *imsg;
  1092.     register struct Gadget *gd;
  1093.     FILE *fp;
  1094.     int done = 0, line = 0, lines, topline, tlines, i;
  1095.     static int once = 0, lastdown;
  1096.     char buf[ 100 ];
  1097.     long loff[ 100 ];
  1098.     long class, code;
  1099.     int txtdiff = scrn->RastPort.TxHeight - 8;
  1100.  
  1101.     if( ( fp = fopen( file, "r" ) ) == NULL )
  1102.     {
  1103. #ifdef  __SASC_60
  1104.     errmsg( FLASH, "Can't open %s: %s", file, strerror(errno) );
  1105. #else
  1106.     errmsg( FLASH, "Can't open %s: %s", file, sys_errlist[errno] );
  1107. #endif
  1108.     return;
  1109.     }
  1110.     for( tlines = 0; tlines < 100 ; ++tlines )
  1111.     {
  1112.     loff[ tlines ] = ftell( fp );
  1113.     if( fgets( buf, sizeof( buf ), fp ) == NULL )
  1114.         break;
  1115.     }
  1116.  
  1117.     if( !once )
  1118.     {
  1119.     for( gd = Help3_NewWindowStructure10.FirstGadget;
  1120.             gd; gd = gd->NextGadget )
  1121.     {
  1122.         if( gd->GadgetID != 0 )
  1123.         {
  1124.         if( gd->GadgetID == GADHELPFRWD ||
  1125.             gd->GadgetID == GADHELPBKWD )
  1126.         {
  1127.             gd->Height += txtdiff;
  1128.         }
  1129.         SetBorder( gd, -1 );
  1130.         }
  1131.     }
  1132.     once = 1;
  1133.     Help3_NewWindowStructure10.Height += txtdiff;
  1134.     }
  1135.  
  1136.     {
  1137.     static char title[40];
  1138.     sprintf(title,"Help for NetHack WorkBench V%d.%d.%d",
  1139.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
  1140.     Help3_NewWindowStructure10.Title = title;
  1141.     }
  1142.  
  1143.     Help3_NewWindowStructure10.Screen = scrn;
  1144.     if( ( win = MyOpenWindow( &Help3_NewWindowStructure10 ) ) == NULL )
  1145.     {
  1146.     errmsg( FLASH, "Can't create requester window" );
  1147.     fclose( fp );
  1148.     return;
  1149.     }
  1150.     lines = ( (win->Height - win->BorderTop - 25 ) / win->RPort->TxHeight );
  1151.     topline = win->BorderTop + win->RPort->TxBaseline + 2;
  1152.     Move( win->RPort, win->BorderLeft, topline );
  1153.  
  1154.     SetAPen( win->RPort, C_BLACK );
  1155.     SetBPen( win->RPort, C_GREY );
  1156.     SetDrMd( win->RPort, JAM2 );
  1157.  
  1158.     for( i = 0; i < min( lines, tlines ); ++i )
  1159.     {
  1160.     getline( fp, loff, i, buf, sizeof( buf ) );
  1161.     Move( win->RPort, win->BorderLeft + 2,
  1162.         topline + (i * win->RPort->TxHeight) );
  1163.     Text( win->RPort, buf, strlen( buf )-1 );
  1164.     }
  1165.  
  1166.     while( !done )
  1167.     {
  1168.     WaitPort( win->UserPort );
  1169.     while( ( imsg = (void *) GetMsg( win->UserPort ) ) != NULL )
  1170.     {
  1171.         class = imsg->Class;
  1172.         code = imsg->Code;
  1173.         gd = (struct Gadget *)imsg->IAddress;
  1174.  
  1175.         ReplyMsg( (struct Message *) imsg );
  1176.  
  1177.         switch( class )
  1178.         {
  1179.         case VANILLAKEY:
  1180.             if( code == 'u' || code == ('U'-64))
  1181.             {
  1182.             goto bkwd;
  1183.             }
  1184.             else if( code == 'd' || code == ('D'-64))
  1185.             {
  1186.             goto frwd;
  1187.             }
  1188.             else if( code == '\33' || code == 'q' )
  1189.             {
  1190.             done = 1;
  1191.             }
  1192.             break;
  1193.  
  1194.         case CLOSEWINDOW:
  1195.             done = 1;
  1196.             break;
  1197.  
  1198.         case MOUSEBUTTONS:
  1199.         case INACTIVEWINDOW:
  1200.         case ACTIVEWINDOW:
  1201.         case GADGETUP:
  1202.             lastdown = 0;
  1203.             break;
  1204.  
  1205.         case GADGETDOWN:
  1206.             lastdown = gd->GadgetID;
  1207.             break;
  1208.  
  1209.         case INTUITICKS:
  1210.             if( lastdown == GADHELPFRWD )
  1211.             {
  1212.             frwd:
  1213.             if( line + lines < tlines )
  1214.             {
  1215.                 line++;
  1216.                 WaitTOF();
  1217.                 ScrollRaster( win->RPort, 0,
  1218.                 win->RPort->TxHeight,
  1219.                 win->BorderLeft,
  1220.                 win->BorderTop + 2,
  1221.                 win->Width - win->BorderRight - 1,
  1222.                 win->BorderTop + 1 +
  1223.                 (lines*win->RPort->TxHeight) );
  1224.                 getline( fp, loff, line + lines - 1,
  1225.                 buf, sizeof( buf ) );
  1226.                 Move( win->RPort, win->BorderLeft + 2,
  1227.                 topline + ( ( lines - 1 ) *
  1228.                 win->RPort->TxHeight ) );
  1229.                 WaitTOF();
  1230.                 Text( win->RPort, buf, strlen( buf )-1 );
  1231.             }
  1232.             else
  1233.             {
  1234.                 /* EOF */
  1235.                 DisplayBeep( scrn );
  1236.                 lastdown = 0;
  1237.             }
  1238.             }
  1239.             else if( lastdown == GADHELPBKWD )
  1240.             {
  1241.             bkwd:
  1242.             if( line > 0 )
  1243.             {
  1244.                 line--;
  1245.                 WaitTOF();
  1246.                 ScrollRaster( win->RPort, 0,
  1247.                 -win->RPort->TxHeight,
  1248.                 win->BorderLeft,
  1249.                 win->BorderTop + 2,
  1250.                 win->Width - win->BorderRight - 1,
  1251.                 win->BorderTop + 1 +
  1252.                 (lines*win->RPort->TxHeight) );
  1253.                 getline( fp, loff, line, buf, sizeof( buf ) );
  1254.                 Move( win->RPort, win->BorderLeft + 2, topline );
  1255.                 WaitTOF();
  1256.                 Text( win->RPort, buf, strlen( buf )-1 );
  1257.             }
  1258.             else
  1259.             {
  1260.                 DisplayBeep( scrn );
  1261.                 lastdown = 0;
  1262.             }
  1263.             }
  1264.             break;
  1265.  
  1266.         }
  1267.     }
  1268.     }
  1269.     SafeCloseWindow( win );
  1270.     fclose( fp );
  1271. }
  1272.  
  1273. /* Act on the menu item number passed */
  1274.  
  1275. void
  1276. do_menu( mptr, mcode)
  1277.     struct Menu *mptr;
  1278.     register int mcode;
  1279. {
  1280.     while( mcode != MENUNULL )
  1281.     {
  1282.     switch(MENUNUM(mcode))
  1283.     {
  1284.         case MENU_PROJECT:
  1285.         switch(ITEMNUM(mcode))
  1286.         {
  1287.             case ITEM_HELP:
  1288.             help_requester( "NetHack:HackWB.hlp" );
  1289.             break;
  1290.  
  1291.             case ITEM_ABOUT:
  1292.             text_requester( &About_NewWindowStructure9,
  1293.                 &About_IntuiTextList9 );
  1294.             break;
  1295.  
  1296.             case ITEM_SCORES:
  1297.             menu_scores( );
  1298.             break;
  1299.  
  1300.             case ITEM_RECOVER:
  1301.             menu_recover( );
  1302.             break;
  1303.  
  1304.             case ITEM_CONFIG:
  1305.             menu_config( );
  1306.             break;
  1307.  
  1308.             case ITEM_QUIT:
  1309.             quit = Ask( "Ready to Quit?" );
  1310.             break;
  1311.  
  1312.         }
  1313.         break;
  1314.  
  1315.         case MENU_GAME:
  1316.         switch( ITEMNUM( mcode ) )
  1317.         {
  1318.  
  1319.             case ITEM_INFO:
  1320.             menu_info( );
  1321.             break;
  1322.  
  1323.             case ITEM_COPYOPT:
  1324.             menu_copyopt( );
  1325.             break;
  1326.  
  1327.             case ITEM_DISCARD:
  1328.             menu_discard( );
  1329.             break;
  1330.  
  1331.             case ITEM_RENAME:
  1332.             menu_rename( );
  1333.             break;
  1334.         }
  1335.     }
  1336.         mcode = ((struct MenuItem *)ItemAddress( mptr, (long)mcode ))->NextSelect;
  1337.     }
  1338. }
  1339.  
  1340. void
  1341. menu_discard()
  1342. {
  1343.     register GPTR gptr;
  1344.  
  1345.     if( ( gptr = NeedGame() ) == NULL )
  1346.     return;
  1347.  
  1348.     if( Ask("Discard Selected Game?") )
  1349.     {
  1350.     lastgaddown = NULL;
  1351.     if( DeleteGame( gptr ) == 0 )
  1352.     {
  1353.         errmsg( FLASH, "Discard may have failed for %s",
  1354.             GameName( gptr, NULL ) );
  1355.     }
  1356.  
  1357.     MapGadgets( R_DISK, 1 );
  1358.     }
  1359. }
  1360.  
  1361. void
  1362. run_game( gptr )
  1363.     register GPTR gptr;
  1364. {
  1365.     extern UWORD __chip waitPointer[];
  1366.     struct Task *ctask;
  1367.     register struct MsgPort *proc = NULL;
  1368.     char buf[ 100 ];
  1369.     char namebuf[ 100 ];
  1370.     int once, tidx;
  1371.  
  1372.     if( gptr->active )
  1373.     {
  1374.     errmsg( FLASH, "%s is already in progress", gptr->name );
  1375.     return;
  1376.     }
  1377.  
  1378.     tidx = 0;
  1379.  
  1380.     /* If newgame gadget, then check game name */
  1381.  
  1382.     if( gptr->dobj->do_Gadget.GadgetID == GADNEWGAME )
  1383.     {
  1384.     once = 0;
  1385.     sprintf( buf, "%s/%s.sav", options[ SAVE_IDX ], gptr->name );
  1386.     while( access( buf, 0 ) == 0 )
  1387.     {
  1388.         if( StrRequest( "Game Already Exists, Enter a New Name",
  1389.         namebuf, once ? namebuf : gptr->gname ) == 0 )
  1390.         {
  1391.         return;
  1392.         }
  1393.         once = 1;
  1394.         sprintf( buf, "%s/%s.sav", options[ SAVE_IDX ], namebuf );
  1395.     }
  1396.     }
  1397.     gptr->gname = xmalloc( 20 + strlen( gptr->name ) );
  1398.  
  1399.     /*
  1400.      * options[] are no longer put into the tooltypes because they are in the options
  1401.      * string now.
  1402.      */
  1403.  
  1404.     gptr->wbs = AllocMem( sizeof( struct WBStartup ) +
  1405.         ( sizeof( struct WBArg ) * 2 ), MEMF_PUBLIC | MEMF_CLEAR );
  1406.  
  1407.     /* Check if we got everything */
  1408.  
  1409.     if( !gptr->gname || !gptr->wbs )
  1410.     {
  1411.     fprintf( stderr, "Can't allocate memory\n" );
  1412.     goto freemem;
  1413.     }
  1414.  
  1415.     /* Get the arguments structure space */
  1416.  
  1417.     gptr->wba = ( struct WBArg * ) ((long)gptr->wbs +
  1418.         sizeof( struct WBStartup ) );
  1419.  
  1420.     /* Close down window and screen if requested */
  1421.  
  1422.     if( shutdown )
  1423.     CloseDownWB( );
  1424.  
  1425.     SetPointer( win, waitPointer, 16, 16, -6, 0 );
  1426.  
  1427.     /* Load the game into memory */
  1428.  
  1429. #ifdef SPLIT
  1430.     /* Which version do we run? */
  1431.     {
  1432.     char gi[80];
  1433.  
  1434.     sprintf( gi, "%s.dir", GAMEIMAGE );
  1435.     if( access( gi, 0 ) == 0 ){
  1436.         gptr->seglist = (BPTR)s_LoadSeg( gi );
  1437.         if( gptr->seglist ) running_split=1;
  1438.     }else{
  1439.         gptr->seglist = (BPTR)LoadSeg( GAMEIMAGE );
  1440.     }
  1441.     }
  1442. #else
  1443.     gptr->seglist = (BPTR)LoadSeg( GAMEIMAGE );
  1444. #endif
  1445.     ClearPointer( win );
  1446.  
  1447.     if( gptr->seglist == NULL)
  1448.     {
  1449.     if( !wbopen )
  1450.         SetupWB( );
  1451.     errmsg( FLASH, "Can't load %s", GAMEIMAGE );
  1452.     goto freemem;
  1453.     }
  1454.     /* Build WBStartup from current game info */
  1455.  
  1456.     /* Set the game name for the status command */
  1457.  
  1458.     sprintf( gptr->gname, "NetHack %d.%d.%d %s",
  1459.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, gptr->name );
  1460.  
  1461.     /* Create a process for the game to execute in */
  1462.  
  1463.     ctask = FindTask( NULL );
  1464.     proc = CreateProc( gptr->gname, ctask->tc_Node.ln_Pri,
  1465.     gptr->seglist, GAMESTACK );
  1466.  
  1467.     /* Check if the create failed */
  1468.  
  1469.     if( proc == NULL )
  1470.     {
  1471.     fprintf(stderr, "Error creating process %d\n", IoErr() );
  1472. #ifdef SPLIT
  1473.     if(!running_split)
  1474. #endif
  1475.         UnLoadSeg( gptr->seglist );
  1476. freemem:
  1477.     if( gptr->gname ) free( gptr->gname );
  1478.     gptr->gname = NULL;
  1479.  
  1480.     if( gptr->wbs ) FreeMem( gptr->wbs,
  1481.     sizeof( struct WBStartup ) + sizeof( struct WBArg ) * 2 );
  1482.     gptr->wbs = NULL;
  1483.     if( !wbopen )
  1484.     SetupWB( );
  1485.     return;
  1486.     }
  1487.  
  1488.     /* Get the Process structure pointer */
  1489.  
  1490.     gptr->prc = (struct Process *) (((long)proc) - sizeof( struct Task ));
  1491.  
  1492.     /* Set the current directory */
  1493.  
  1494.     gptr->prc->pr_CurrentDir=((struct Process *)FindTask(NULL))->pr_CurrentDir;
  1495.  
  1496.     /* Fill in the startup message */
  1497.  
  1498.     gptr->wbs->sm_Process = proc;
  1499.     gptr->wbs->sm_Segment = gptr->seglist;
  1500.     gptr->wbs->sm_NumArgs = 2;
  1501.     {
  1502.     static char tw[40];
  1503.     sprintf(tw,"con:0/0/350/50/Amiga NetHack %d.%d.%d",
  1504.       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
  1505.     gptr->wbs->sm_ToolWindow = tw;
  1506.     }
  1507.     gptr->wbs->sm_ArgList = gptr->wba;
  1508.  
  1509.     /* Fill in the args */
  1510.  
  1511.     gptr->wba[0].wa_Name = Strdup( GAMEIMAGE );
  1512.     gptr->wba[0].wa_Lock = Lock( dirname( GAMEIMAGE ), ACCESS_READ );
  1513.  
  1514.     gptr->wba[1].wa_Name = Strdup( gptr->name );
  1515.     gptr->wba[1].wa_Lock = Lock( gptr->dname, ACCESS_READ );
  1516.  
  1517.     /* Write the updated tools types entries */
  1518.  
  1519.     WriteDObj( gptr, gptr->wba[1].wa_Lock );
  1520.  
  1521.     /* Set the message fields correctly */
  1522.  
  1523.     gptr->wbs->sm_Message.mn_Node.ln_Type = NT_MESSAGE;
  1524.     gptr->wbs->sm_Message.mn_Node.ln_Pri = 0;
  1525.     gptr->wbs->sm_Message.mn_ReplyPort = dosport;
  1526.     gptr->wbs->sm_Message.mn_Length =
  1527.     sizeof( struct WBStartup ) + ( sizeof( struct WBArg ) * 2 );
  1528.  
  1529.     /* mark game as in use */
  1530.  
  1531.     active_count++;
  1532.     gptr->active = 1;
  1533.  
  1534.     /* Send the WB Startup message to let the game go... */
  1535.  
  1536.     PutMsg( proc, &gptr->wbs->sm_Message );
  1537. }
  1538.  
  1539. void CloseLibraries( )
  1540. {
  1541.     if( IntuitionBase )     CloseLibrary( (void *) IntuitionBase );
  1542.     IntuitionBase = 0;
  1543.     if( DiskfontBase )      CloseLibrary( (void *) DiskfontBase );
  1544.     DiskfontBase = 0;
  1545.     if( IconBase )          CloseLibrary(  IconBase );
  1546.     IconBase = 0;
  1547.     if( GfxBase )           CloseLibrary( (void *) GfxBase );
  1548.     GfxBase = 0;
  1549. }
  1550.  
  1551. void cleanup( code )
  1552.     int code;
  1553. {
  1554.     if( active_count )
  1555.     {
  1556.     errmsg( FLASH, "There %s still %d game%s active...",
  1557.         active_count > 1 ? "are" : "is",
  1558.         active_count,
  1559.         active_count > 1 ? "s" : "" );
  1560.     return;
  1561.     }
  1562.  
  1563.     if( dosport ) DeletePort( dosport );
  1564.     dosport = NULL;
  1565.  
  1566.     CloseDownWB( );
  1567.     CleanUpLists( );
  1568.     CloseLibraries( );
  1569.  
  1570. #ifdef SPLIT
  1571.     if(running_split)s_UnLoadSeg();
  1572. #endif
  1573.     exit( code );
  1574. }
  1575.  
  1576. GPTR AllocGITEM( )
  1577. {
  1578.     register GPTR gptr;
  1579.  
  1580.     if( gameavail )
  1581.     {
  1582.     gptr = gameavail;
  1583.     gameavail = gameavail->next;
  1584.     }
  1585.     else
  1586.     {
  1587.     gptr = xmalloc( sizeof( GAMEITEM ) );
  1588.     }
  1589.  
  1590.     if( gptr )
  1591.     memset( gptr, 0, sizeof( GAMEITEM ) );
  1592.  
  1593.     return( gptr );
  1594. }
  1595.  
  1596. void FreeGITEM( gptr )
  1597.     register GPTR gptr;
  1598. {
  1599.     /* Free all of the pieces first */
  1600.  
  1601.     if( gptr->talloc )
  1602.     FreeTools( gptr );
  1603.  
  1604.     if( gptr->dobj )
  1605.     FreeDObj( gptr->dobj );
  1606.  
  1607.     gptr->dobj = NULL;
  1608.  
  1609.     if( gptr->name )
  1610.     free( gptr->name );
  1611.     gptr->name = NULL;
  1612.  
  1613.     if( gptr->dname )
  1614.     free( gptr->dname );
  1615.     gptr->dname = NULL;
  1616.  
  1617.     if( gptr->fname )
  1618.     free( gptr->fname );
  1619.     gptr->fname = NULL;
  1620.  
  1621.     /* Connect it to free list */
  1622.  
  1623.     gptr->next = gameavail;
  1624.     gameavail = gptr;
  1625. }
  1626.  
  1627. struct DiskObject *AllocDObj( str )
  1628.     register char *str;
  1629. {
  1630.     register struct DiskObject *doptr;
  1631.     register char *t, *t1;
  1632.  
  1633.     if( ( t = strrchr( str, '.' ) ) && stricmp( t, ".info" ) == 0 )
  1634.     {
  1635.     *t = 0;
  1636.     }
  1637.     else
  1638.     {
  1639.     t = NULL;
  1640.     }
  1641.  
  1642.     if( doptr = GetDiskObject( str ) )
  1643.     {
  1644.     struct IntuiText *ip;
  1645.  
  1646.     diskobj_filter(doptr);  /* delete INTERNALCLI */
  1647.  
  1648.     if( ip = xmalloc( sizeof( struct IntuiText ) ) )
  1649.     {
  1650.         memset( ip, 0, sizeof( struct IntuiText ) );
  1651.         ip->FrontPen = C_BLACK;
  1652.         ip->DrawMode = JAM1;
  1653.         ip->LeftEdge = (doptr->do_Gadget.Width -
  1654.         ( strlen( str ) * win->RPort->TxWidth ))/2;
  1655.         ip->TopEdge = doptr->do_Gadget.Height;
  1656.         ip->IText = strdup( str );
  1657.         doptr->do_Gadget.GadgetText = ip;
  1658.  
  1659.         /* Trim any .sav off of the end. */
  1660.  
  1661.         if( ( t1 = strrchr( ip->IText, '.' ) ) &&
  1662.             stricmp( t1, ".sav" ) == 0 )
  1663.         {
  1664.         *t1 = 0;
  1665.         ip->LeftEdge += (2 * win->RPort->TxWidth);
  1666.         }
  1667.     }
  1668.     }
  1669.     if( t ) *t = '.';
  1670.  
  1671.     return( doptr );
  1672. }
  1673.  
  1674. void LoadIcons( )
  1675. {
  1676.     register GPTR gptr, newgame;
  1677.     register BPTR savedir;
  1678.     register char *t;
  1679.     register struct FileInfoBlock *finfo;
  1680.     char buf[ 200 ];
  1681.  
  1682.     /* Check if we can access the new save directory */
  1683.  
  1684.     if( t = strchr( options[ SAVE_IDX ], ';' ) )
  1685.     {
  1686.     strncpy( buf, options[ SAVE_IDX ], sizeof( buf ) - 1 );
  1687.     buf[ sizeof( buf ) - 1 ] = 0;
  1688.     if( ( t = strchr( buf, ';' ) ) && strcmp( t, ";n" ) == 0 )
  1689.         *t = 0;
  1690.     if( ( savedir = Lock( buf, ACCESS_READ ) ) == NULL )
  1691.     {
  1692.         errmsg( FLASH,
  1693.             "Can't access save directory: %s", buf );
  1694.         return;
  1695.     }
  1696.     }
  1697.     else if( ( savedir = Lock( options[ SAVE_IDX ], ACCESS_READ ) ) == NULL )
  1698.     {
  1699.     errmsg( FLASH,
  1700.         "Can't access save directory: %s", options[ SAVE_IDX ] );
  1701.     return;
  1702.     }
  1703.  
  1704.     if( ( finfo = (struct FileInfoBlock *)
  1705.             xmalloc( sizeof( struct FileInfoBlock ) ) ) == NULL )
  1706.     {
  1707.     UnLock( savedir );
  1708.     errmsg( FLASH, "Can't alloc memory" );
  1709.     return;
  1710.     }
  1711.  
  1712.     if( ( newgame = gamehead ) && newgame->dobj->do_Gadget.GadgetID == GADNEWGAME )
  1713.     gamehead = gamehead->next;
  1714.     else
  1715.     newgame = NULL;
  1716.  
  1717.     if( !Examine( savedir, finfo ) )
  1718.     {
  1719.     UnLock( savedir );
  1720.     free( finfo );
  1721.     errmsg( FLASH, "Can't Examine save directory" );
  1722.     return;
  1723.     }
  1724.  
  1725.     /* Collect all of the entries */
  1726.  
  1727.     while( ExNext( savedir, finfo ) )
  1728.     {
  1729.     /* If already got this game, continue */
  1730.  
  1731.     if( gptr = FindGame( finfo->fib_FileName ) )
  1732.         continue;
  1733.  
  1734.     /* Get just the ones we are interested in */
  1735.  
  1736.     if( ( t = strrchr( finfo->fib_FileName, '.' ) ) == NULL ||
  1737.             stricmp( t, ".info" ) != 0 )
  1738.         continue;
  1739.  
  1740.     if( t == finfo->fib_FileName )
  1741.         continue;
  1742.  
  1743.     /* Get a gadget item */
  1744.  
  1745.     if( gptr = GetWBIcon( savedir, options[ SAVE_IDX ], finfo ) )
  1746.     {
  1747.         gptr->next = gamehead;
  1748.         gamehead = gptr;
  1749.     }
  1750.     }
  1751.  
  1752.     /* Get the NewGame gadget */
  1753.  
  1754.     UnLock( savedir );
  1755.     if( newgame == NULL )
  1756.     {
  1757.     /* Pick up the new game if not there yet. */
  1758.  
  1759.     sprintf( buf, "%sNewGame.info", options[ HACKDIR_IDX ] );
  1760.     if( savedir = Lock( buf, ACCESS_READ ) )
  1761.     {
  1762.         if( Examine( savedir, finfo ) )
  1763.         {
  1764.         UnLock( savedir );
  1765.         savedir = Lock( options[ HACKDIR_IDX ], ACCESS_READ );
  1766.         if( gptr = GetWBIcon( savedir,
  1767.             options[ HACKDIR_IDX ], finfo ) )
  1768.         {
  1769.             gptr->next = gamehead;
  1770.             gamehead = gptr;
  1771.         }
  1772.         }
  1773.         UnLock( savedir );
  1774.         free( finfo );
  1775.     }
  1776.     else
  1777.     {
  1778.         errmsg( FLASH, "No access to %s", buf );
  1779.     }
  1780.     }
  1781.     else
  1782.     {
  1783.     newgame->next = gamehead;
  1784.     gamehead = newgame;
  1785.     }
  1786. }
  1787.  
  1788. void menu_recover()
  1789. {
  1790.     int execit = 1;
  1791.     long class, code;
  1792.     struct Gadget *gd, *lastact = 0;
  1793.     int done = 0;
  1794.     struct IntuiMessage *imsg;
  1795.     struct Window *w;
  1796.     static int once = 0;
  1797.     int txtdiff = scrn->RastPort.TxHeight - 8;
  1798.     struct IntuiText *ip;
  1799.  
  1800.     if( !once )
  1801.     {
  1802.     for( gd = Rst_NewWindowStructure11.FirstGadget;
  1803.             gd; gd = gd->NextGadget )
  1804.     {
  1805.         switch( gd->GadgetID )
  1806.         {
  1807.         case GADRESTDIR:
  1808.             gd->TopEdge += txtdiff;
  1809.             gd->Height += txtdiff;
  1810.             SetBorder( gd, -1 );
  1811.             strcpy(RstDir,options[LEVELS_IDX]);
  1812.             break;
  1813.         case GADRESTOLD:
  1814.             gd->TopEdge += txtdiff*2;
  1815.             gd->Height += txtdiff;
  1816.             SetBorder( gd, -1 );
  1817.             strcpy(RstOld,"levels");
  1818.             break;
  1819.         case GADRESTNEW:
  1820.             gd->TopEdge += txtdiff*3;
  1821.             gd->Height += txtdiff;
  1822.             SetBorder( gd, -1 );
  1823.             break;
  1824.         case GADRESTOKAY:
  1825.             gd->TopEdge += txtdiff*4;
  1826.             gd->Height += txtdiff;
  1827.             SetBorder( gd, -1 );
  1828.             break;
  1829.         case GADRESTCAN:
  1830.             gd->TopEdge += txtdiff*4;
  1831.             gd->Height += txtdiff;
  1832.             SetBorder( gd, -1 );
  1833.             break;
  1834.         }
  1835.     }
  1836.     Rst_NewWindowStructure11.Height += txtdiff*5;
  1837.     for( ip = &Rst_IntuiTextList11; ip; ip = ip->NextText )
  1838.     {
  1839.         if( *ip->IText == 'O' )
  1840.         ip->TopEdge += txtdiff;
  1841.         else if( *ip->IText == 'N' )
  1842.         ip->TopEdge += txtdiff*2;
  1843.     }
  1844.     once = 1;
  1845.     }
  1846.  
  1847.     Rst_NewWindowStructure11.Screen = scrn;
  1848.     if( ( w = MyOpenWindow( &Rst_NewWindowStructure11 ) ) == NULL )
  1849.     {
  1850.     errmsg( FLASH, "Can't create requester window" );
  1851.     return;
  1852.     }
  1853.     PrintIText( w->RPort, &Rst_IntuiTextList11, 0, txtdiff );
  1854.     lastact = FindGadget( w, NULL, GADRESTDIR );
  1855.  
  1856.     while( !done )
  1857.     {
  1858.     WaitPort( w->UserPort );
  1859.     while( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) )
  1860.     {
  1861.         class = imsg->Class;
  1862.         code = imsg->Code;
  1863.         gd = (struct Gadget *)imsg->IAddress;
  1864.         ReplyMsg( (struct Message *) imsg );
  1865.         switch( class )
  1866.         {
  1867.         case CLOSEWINDOW:
  1868.             done = 1;
  1869.             execit = 0;
  1870.             break;
  1871.  
  1872.         case ACTIVEWINDOW:
  1873.             ActivateGadget( lastact, w, NULL );
  1874.             break;
  1875.  
  1876.         case GADGETUP:
  1877.             if( gd->GadgetID == GADRESTOKAY )
  1878.             done = 1;
  1879.             else if( gd->GadgetID == GADRESTCAN )
  1880.             {
  1881.             execit = 0;
  1882.             done = 1;
  1883.             }
  1884.             else if( gd->GadgetID == GADRESTDIR )
  1885.             {
  1886.             if( gd = FindGadget( w, NULL, GADRESTOLD ) )
  1887.                 ActivateGadget( lastact = gd, w, NULL );
  1888.             }
  1889.             else if( gd->GadgetID == GADRESTOLD )
  1890.             {
  1891.             if( gd = FindGadget( w, NULL, GADRESTNEW ) )
  1892.                 ActivateGadget( lastact = gd, w, NULL );
  1893.             }
  1894.             break;
  1895.  
  1896.         case VANILLAKEY:
  1897.             if( code == '\33' )
  1898.             {
  1899.             done = 1;
  1900.             execit = 0;
  1901.             }
  1902.             break;
  1903.         }
  1904.     }
  1905.     }
  1906.  
  1907.     SafeCloseWindow( w );
  1908.  
  1909.     if( execit )
  1910.     {
  1911.     char buf[255];
  1912.     sprintf( buf, "stack 65000\nNetHack:Recover -d %s %s", RstDir, RstOld );
  1913.     Execute( buf, NULL, NULL );
  1914.     MapGadgets( R_DISK, 1);
  1915.     }
  1916. }
  1917.  
  1918. void menu_config()
  1919. {
  1920.     register struct Window *cwin;
  1921.     int done = 0, quit;
  1922.     long class, code, qual;
  1923.     register struct IntuiMessage *imsg;
  1924.     struct IntuiText *ip;
  1925.     register struct Gadget *gd;
  1926.     static int once = 0;
  1927.     int txtdiff = scrn->RastPort.TxHeight - 8;
  1928.     char *env;
  1929.  
  1930.     strcpy( StrPath, options[ PATH_IDX ] );
  1931.     strcpy( StrHackdir, options[ HACKDIR_IDX ] );
  1932.     strcpy( StrPens, options[ PENS_IDX ] );
  1933.     strcpy( StrLevels, options[ LEVELS_IDX ] );
  1934.     strcpy( StrSave, options[ SAVE_IDX ] );
  1935.  
  1936.     if( !once )
  1937.     {
  1938.     for( gd = Conf_NewWindowStructure4.FirstGadget;
  1939.             gd; gd = gd->NextGadget )
  1940.     {
  1941.         switch( gd->GadgetID )
  1942.         {
  1943.         case GADSTRPATH:
  1944.             /* Look for "Path:" string */
  1945.             for( ip = &Conf_IntuiTextList4;
  1946.                 ip && *ip->IText != 'P'; )
  1947.             ip = ip->NextText;
  1948.             gd->TopEdge += txtdiff;
  1949.             gd->Height += txtdiff;
  1950.             SetBorder( gd, -1 );
  1951.             break;
  1952.         case GADSTRHACKDIR:
  1953.             /* Look for "Hackdir:" string */
  1954.             for( ip = &Conf_IntuiTextList4;
  1955.                 ip && *ip->IText != 'H'; )
  1956.             ip = ip->NextText;
  1957.             if( ip )
  1958.             ip->TopEdge += txtdiff;
  1959.             gd->TopEdge += txtdiff*2;
  1960.             gd->Height += txtdiff;
  1961.             SetBorder( gd, -1 );
  1962.             break;
  1963.         case GADSTRPENS:
  1964.             /* Look for "Pens:" string */
  1965.             for( ip = &Conf_IntuiTextList4; ip &&
  1966.             !(*ip->IText == 'P' && ip->IText[1] == 'e'); )
  1967.             {
  1968.             ip = ip->NextText;
  1969.             }
  1970.             if( ip )
  1971.             ip->TopEdge += txtdiff*2;
  1972.             gd->TopEdge += txtdiff*3;
  1973.             gd->Height += txtdiff;
  1974.             SetBorder( gd, -1 );
  1975.             break;
  1976.         case GADSTRLEVELS:
  1977.             /* Look for "Levels:" string */
  1978.             for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'L'; )
  1979.             ip = ip->NextText;
  1980.             if( ip )
  1981.             ip->TopEdge += txtdiff*3;
  1982.             gd->TopEdge += txtdiff*4;
  1983.             gd->Height += txtdiff;
  1984.             SetBorder( gd, -1 );
  1985.             break;
  1986.         case GADSTRSAVE:
  1987.             /* Look for "Save Dir:" string */
  1988.             for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'S'; )
  1989.             ip = ip->NextText;
  1990.             if( ip )
  1991.             ip->TopEdge += txtdiff*4;
  1992.             gd->TopEdge += txtdiff*5;
  1993.             gd->Height += txtdiff;
  1994.             SetBorder( gd, -1 );
  1995.             break;
  1996.         case GADCONFLOAD:
  1997.         case GADCONFSAVE:
  1998.             gd->TopEdge += txtdiff*6;
  1999.             gd->Height += txtdiff;
  2000.             SetBorder( gd, -1 );
  2001.             break;
  2002.         case GADCONFNAME:
  2003.             for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'C'; )
  2004.             ip = ip->NextText;
  2005.             if( ip )
  2006.             ip->TopEdge += txtdiff*6;
  2007.             gd->TopEdge += txtdiff*7;
  2008.             gd->Height += txtdiff;
  2009.             SetBorder( gd, -1 );
  2010.             break;
  2011.  
  2012.         default:
  2013.             break;
  2014.         }
  2015.     }
  2016.     Conf_NewWindowStructure4.Height += txtdiff*8;
  2017.     if( Conf_NewWindowStructure4.TopEdge +
  2018.         Conf_NewWindowStructure4.Height > scrn->Height )
  2019.     {
  2020.         Conf_NewWindowStructure4.TopEdge -=
  2021.         ( Conf_NewWindowStructure4.TopEdge +
  2022.         Conf_NewWindowStructure4.Height ) - scrn->Height + 1;
  2023.         if( Conf_NewWindowStructure4.TopEdge < 0 )
  2024.         {
  2025.         Conf_NewWindowStructure4.TopEdge = 0;
  2026.         Conf_NewWindowStructure4.Height = scrn->Height - 1;
  2027.         }
  2028.     }
  2029.     once = 1;
  2030.     }
  2031.  
  2032.     Conf_NewWindowStructure4.Screen = scrn;
  2033.     if( ( cwin = MyOpenWindow( &Conf_NewWindowStructure4 ) ) == NULL )
  2034.     {
  2035.     errmsg( FLASH, "Can't create requester window" );
  2036.     return;
  2037.     }
  2038.  
  2039.     PrintIText( cwin->RPort, &Conf_IntuiTextList4, 0, txtdiff );
  2040.     while( !done )
  2041.     {
  2042.     WaitPort( cwin->UserPort );
  2043.     while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
  2044.     {
  2045.         class = imsg->Class;
  2046.         code = imsg->Code;
  2047.         qual = imsg->Qualifier;
  2048.         gd = (struct Gadget *)imsg->IAddress;
  2049.  
  2050.         ReplyMsg( (struct Message *)imsg );
  2051.  
  2052.         switch( class )
  2053.         {
  2054.         case VANILLAKEY:
  2055.             if( code == '\33' || (code == 'b' && (qual&AMIGALEFT)))
  2056.             {
  2057.             done = 0;
  2058.             quit = 1;
  2059.             }
  2060.             break;
  2061.  
  2062.         case ACTIVEWINDOW:
  2063.             if( gd = FindGadget( cwin, NULL, GADCONFNAME ) )
  2064.             ActivateGadget( gd, cwin, NULL );
  2065.             break;
  2066.  
  2067.         case CLOSEWINDOW:
  2068.             done = 1;
  2069.             quit = 0;
  2070.             break;
  2071.  
  2072.         case GADGETUP:
  2073.             switch( gd->GadgetID )
  2074.             {
  2075.             case GADSTRPATH:
  2076.                 if( gd = FindGadget( cwin, NULL,GADSTRHACKDIR) )
  2077.                 ActivateGadget( gd, cwin, NULL );
  2078.                 break;
  2079.             case GADSTRHACKDIR:
  2080.                 if( gd = FindGadget( cwin, NULL,GADSTRPENS) )
  2081.                 ActivateGadget( gd, cwin, NULL );
  2082.                 break;
  2083.             case GADSTRPENS:
  2084.                 if( gd = FindGadget( cwin, NULL,GADSTRLEVELS) )
  2085.                 ActivateGadget( gd, cwin, NULL );
  2086.                 break;
  2087.             case GADSTRLEVELS:
  2088.                 if( gd = FindGadget( cwin, NULL, GADSTRSAVE ) )
  2089.                 ActivateGadget( gd, cwin, NULL );
  2090.                 break;
  2091.             case GADSTRSAVE:
  2092.                 if( gd = FindGadget( cwin, NULL, GADCONFNAME ) )
  2093.                 ActivateGadget( gd, cwin, NULL );
  2094.                 break;
  2095.  
  2096.             case GADCONFNAME:    /* Do nothing... */
  2097.                 break;
  2098.  
  2099.             case GADCONFLOAD:
  2100.                 ReadConfig( );
  2101.                             env = malloc( strlen( StrConf ) + 3 +
  2102.                         strlen( "NETHACKOPTIONS" ) );
  2103.                 sprintf( env, "NETHACKOPTIONS=@%s", StrConf );
  2104.                 putenv( env );
  2105.                 free( env );
  2106.                 strcpy( StrPath, options[ PATH_IDX ] );
  2107.                 strcpy( StrHackdir, options[ HACKDIR_IDX ] );
  2108.                 strcpy( StrPens, options[ PENS_IDX ] );
  2109.                 strcpy( StrLevels, options[ LEVELS_IDX ] );
  2110.                 strcpy( StrSave, options[ SAVE_IDX ] );
  2111.                 RefreshGList( cwin->FirstGadget, cwin, NULL, -1 );
  2112.                 break;
  2113.  
  2114.             case GADCONFSAVE:
  2115.                     {
  2116.                         FILE *fp, *nfp;
  2117.                         char buf[ 300 ], *t, nname[ 100 ], oname[100], *b;
  2118.  
  2119.                                 setoneopt( PATH_IDX, StrPath );
  2120.                                 setoneopt( HACKDIR_IDX, StrHackdir );
  2121.                                 setoneopt( PENS_IDX, StrPens );
  2122.                                 setoneopt( LEVELS_IDX, StrLevels );
  2123.                                 setoneopt( SAVE_IDX, StrSave );
  2124.  
  2125.                     fp = fopen( StrConf, "r" );
  2126.                     if( !fp )
  2127.                     {
  2128.                     fp = fopen( "NetHack:NetHack.cnf", "r" );
  2129.                     strcpy( StrConf, "NetHack:NetHack.cnf" );
  2130.                 }
  2131.                     if( !fp )
  2132.                     {
  2133.                                 errmsg( FLASH, "Can't open config file" );
  2134.                                 break;
  2135.                             }
  2136.  
  2137.                               t = dirname( StrConf );
  2138.                             b = basename( StrConf );
  2139.                               if( t[ strlen(t)-1 ] == ':' )
  2140.                               {
  2141.                                   sprintf( nname, "%snew_%s", t, b);
  2142.                                   sprintf( oname, "%sold_%s", t, b);
  2143.                             }
  2144.                              else
  2145.                 {
  2146.                                     sprintf( oname, "%s/old_%s", t, b);
  2147.                                     sprintf( nname, "%s/new_%s", t, b);
  2148.                             }
  2149.  
  2150.                     nfp = fopen( nname, "w" );
  2151.                     if( !nfp )
  2152.                     {
  2153.                                 errmsg( FLASH, "Can't open new config file for write" );
  2154.                                 fclose( fp );
  2155.                                 break;
  2156.                             }
  2157.  
  2158.                     while( fgets( buf, sizeof( buf ), fp ) )
  2159.                     {
  2160.                         if( strncmp( buf, "PATH=", 5 ) == 0 )
  2161.                             fprintf( nfp, "PATH=%s\n",
  2162.                         options[ PATH_IDX ] );
  2163.                         else if( strncmp( buf, "LEVELS=", 7 ) == 0 )
  2164.                             fprintf( nfp, "LEVELS=%s\n",
  2165.                         options[ LEVELS_IDX ] );
  2166.                         else if( strncmp( buf, "PENS=", 5 ) == 0 )
  2167.                             fprintf( nfp, "PENS=%s\n",
  2168.                         options[ PENS_IDX ] );
  2169.                         else if( strncmp( buf, "OPTIONS=", 8 ) == 0 )
  2170.                             fprintf( nfp, "OPTIONS=%s\n",
  2171.                         options[ OPTIONS_IDX ] );
  2172.                         else if( strncmp( buf, "SAVE=", 5 ) == 0 )
  2173.                             fprintf( nfp, "SAVE=%s\n",
  2174.                         options[ SAVE_IDX ] );
  2175.                         else if( strncmp( buf, "HACKDIR=", 8 ) == 0 )
  2176.                             fprintf( nfp, "HACKDIR=%s\n",
  2177.                         options[ HACKDIR_IDX ] );
  2178.                         else
  2179.                         {
  2180.                             fputs( buf, nfp );
  2181.                         }
  2182.                     }
  2183.                     fclose( fp );
  2184.                     fclose( nfp );
  2185.                     unlink( oname );
  2186.                     rename( StrConf, oname );
  2187.                     rename( nname, StrConf );
  2188.                     }
  2189.                 break;
  2190.  
  2191.             default:
  2192.                 break;
  2193.             }
  2194.             break;
  2195.         }
  2196.     }
  2197.     }
  2198.  
  2199.     setoneopt( PATH_IDX, StrPath );
  2200.     setoneopt( HACKDIR_IDX, StrHackdir );
  2201.     setoneopt( PENS_IDX, StrPens );
  2202.     setoneopt( LEVELS_IDX, StrLevels );
  2203.     setoneopt( SAVE_IDX, StrSave );
  2204.  
  2205.     SafeCloseWindow( cwin );
  2206.  
  2207.     /* Display icons in possibly new save directory */
  2208.  
  2209.     MapGadgets( R_DISK, 1 );
  2210. }
  2211.  
  2212. void
  2213. UpdateCnfFile()
  2214. {
  2215.     FILE *fp, *nfp;
  2216.     char buf[ 300 ];
  2217.     char path=0,option=0,dir=0,pens=0,levels=0,save=0;
  2218.     char oname[ 300 ], nname[ 300 ];
  2219.  
  2220.     setoneopt( PATH_IDX, StrPath );
  2221.     PutOptions( curopts );
  2222.     setoneopt( HACKDIR_IDX, StrHackdir );
  2223.     setoneopt( PENS_IDX, StrPens );
  2224.     setoneopt( LEVELS_IDX, StrLevels );
  2225.     setoneopt( SAVE_IDX, StrSave );
  2226.  
  2227.     strcpy( oname, dirname( StrConf ) );
  2228.     if( oname[ strlen(oname)-1 ] != ':' )
  2229.     {
  2230.     sprintf( nname, "%s/new_nethack.cnf", oname );
  2231.     strcat( oname, "/" );
  2232.     strcat( oname, "old_nethack.cnf" );
  2233.     }
  2234.     else
  2235.     {
  2236.     sprintf( nname, "%snew_nethack.cnf", oname );
  2237.     strcat( oname, "old_nethack.cnf" );
  2238.     }
  2239.  
  2240.     fp = fopen( StrConf, "r" );
  2241.     if( !fp )
  2242.     {
  2243.         errmsg( FLASH, "Can't open nethack.cnf" );
  2244.         return;
  2245.     }
  2246.     nfp = fopen( nname, "w" );
  2247.     if( !nfp )
  2248.     {
  2249.         sprintf( buf, "Can't open %s for write", nname );
  2250.         errmsg( FLASH, buf );
  2251.         fclose( fp );
  2252.         return;
  2253.     }
  2254.     while( fgets( buf, sizeof( buf ), fp ) )
  2255.     {
  2256.         if( strncmp( buf, "PATH=", 5 ) == 0 )
  2257.     {
  2258.             fprintf( nfp, "PATH=%s\n", options[ PATH_IDX ] );
  2259.         path=1;
  2260.     }
  2261.         else if( strncmp( buf, "LEVELS=", 7 ) == 0 )
  2262.     {
  2263.             fprintf( nfp, "LEVELS=%s\n", options[ LEVELS_IDX ] );
  2264.         levels=1;
  2265.     }
  2266.         else if( strncmp( buf, "PENS=", 5 ) == 0 )
  2267.     {
  2268.             fprintf( nfp, "PENS=%s\n", options[ PENS_IDX ] );
  2269.         pens=1;
  2270.     }
  2271.         else if( strncmp( buf, "OPTIONS=", 8 ) == 0 )
  2272.     {
  2273.             fprintf( nfp, "OPTIONS=%s\n", options[ OPTIONS_IDX ] );
  2274.         option=1;
  2275.     }
  2276.         else if( strncmp( buf, "SAVE=", 5 ) == 0 )
  2277.     {
  2278.             fprintf( nfp, "SAVE=%s\n", options[ SAVE_IDX ] );
  2279.         save=1;
  2280.     }
  2281.         else if( strncmp( buf, "HACKDIR=", 8 ) == 0 )
  2282.     {
  2283.             fprintf( nfp, "HACKDIR=%s\n", options[ HACKDIR_IDX ] );
  2284.         dir=1;
  2285.     }
  2286.         else
  2287.         {
  2288.                fputs( buf, nfp );
  2289.         }
  2290.     }
  2291.  
  2292.     /* Write any that weren't already in the file */
  2293.     if( !path )
  2294.         fprintf( nfp, "PATH=%s\n", options[ PATH_IDX ] );
  2295.     if( !levels )
  2296.         fprintf( nfp, "LEVELS=%s\n", options[ LEVELS_IDX ] );
  2297.     if( !pens )
  2298.         fprintf( nfp, "PENS=%s\n", options[ PENS_IDX ] );
  2299.     if( !option )
  2300.         fprintf( nfp, "OPTIONS=%s\n", options[ OPTIONS_IDX ] );
  2301.     if( !save )
  2302.         fprintf( nfp, "SAVE=%s\n", options[ SAVE_IDX ] );
  2303.     if( !dir )
  2304.         fprintf( nfp, "HACKDIR=%s\n", options[ HACKDIR_IDX ] );
  2305.  
  2306.     /* Close up and rename files */
  2307.     fclose( fp );
  2308.     fclose( nfp );
  2309.     unlink( oname );
  2310.     if( filecopy( StrConf, oname ) == 0 )
  2311.     filecopy( nname, StrConf );
  2312. }
  2313.  
  2314. filecopy( from, to )
  2315.     char *from, *to;
  2316. {
  2317.     char *buf;
  2318.     int i = 0;
  2319.  
  2320.     buf = malloc( strlen(to) + strlen(from) + 20 );
  2321.     if( buf )
  2322.     {
  2323.         sprintf( buf, "c:copy \"%s\" \"%s\" clone", from, to );
  2324.  
  2325.         /* Check SysBase instead?  Shouldn't matter  */
  2326.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  2327.         i = System( buf, NULL );
  2328.     else
  2329.         Execute( buf, NULL, NULL );
  2330.         free( buf );
  2331.     }
  2332.     else
  2333.     {
  2334.         errmsg( FLASH, "Failed to allocate memory for copy command" );
  2335.         return( -1 );
  2336.     }
  2337.     return( i );
  2338. }
  2339.  
  2340. void do_gadgetup( imsg )
  2341.     register struct IntuiMessage *imsg;
  2342. {
  2343.     register struct Gadget *gd;
  2344.     register unsigned long hid;
  2345.     int ncol, pot;
  2346.  
  2347.     gd = (struct Gadget *) imsg->IAddress;
  2348.  
  2349.     switch( gd->GadgetID )
  2350.     {
  2351.     case GADSCROLL:
  2352.         hid = max( cols - vcols, 0 );
  2353.         pot = ( ( struct PropInfo * ) gd->SpecialInfo )->HorizPot;
  2354.         ncol = (hid * pot) / MAXPOT;
  2355.         if( ncol != curcol )
  2356.         {
  2357.         curcol = ncol;
  2358.         MapGadgets( R_SCROLL, 0 ); /* redisplay the icons */
  2359.         }
  2360.         break;
  2361.     }
  2362. }
  2363.  
  2364. void do_buttons( imsg )
  2365.     register struct IntuiMessage *imsg;
  2366. {
  2367.     if( imsg->Code == SELECTDOWN || imsg->Code == SELECTUP )
  2368.     {
  2369.     if( lastgaddown )
  2370.     {
  2371.         SetGadgetUP( &lastgaddown->dobj->do_Gadget );
  2372.         lastgaddown->secs = 0;
  2373.         lastgaddown->mics = 0;
  2374.     }
  2375.     lastgaddown = NULL;
  2376.     ChgGameItems( &MenuList1, 0 );
  2377.     }
  2378. }
  2379.  
  2380. void do_gadgetdown( imsg )
  2381.     register struct IntuiMessage *imsg;
  2382. {
  2383.     register GPTR gptr;
  2384.     register struct Gadget *gd;
  2385.  
  2386.     gd = (struct Gadget *) imsg->IAddress;
  2387.  
  2388.     /* Don't do anything for these gadgets */
  2389.  
  2390.     if( gd->GadgetID < GADNEWGAME )
  2391.     {
  2392.     return;
  2393.     }
  2394.  
  2395.     /* Check just to make sure we got it */
  2396.  
  2397.     for( gptr = windowgads; gptr &&
  2398.     gptr->dobj->do_Gadget.GadgetID != gd->GadgetID; )
  2399.     {
  2400.     gptr = gptr->nextwgad;
  2401.     }
  2402.  
  2403.     if( !gptr )
  2404.     {
  2405.     errmsg( FLASH, "Bad GadgetID for GadgetDOWN" );
  2406.     return;
  2407.     }
  2408.  
  2409.     /* Fix the gadget images */
  2410.  
  2411.     if( lastgaddown && &lastgaddown->dobj->do_Gadget != gd )
  2412.     {
  2413.     SetGadgetUP( &lastgaddown->dobj->do_Gadget );
  2414.     gptr->secs = 0;
  2415.     gptr->mics = 0;
  2416.     }
  2417.     SetGadgetDOWN( &((lastgaddown = gptr)->dobj->do_Gadget) );
  2418.  
  2419.     /* Only allow game gadgets to be manipulated */
  2420.  
  2421.     if( lastgaddown->dobj->do_Gadget.GadgetID == GADNEWGAME )
  2422.     ChgNewGameItems( &MenuList1, 1 );
  2423.     else
  2424.     ChgGameItems( &MenuList1, 1 );
  2425.  
  2426.     /* Check if this gadget has been double clicked */
  2427.  
  2428.     if( DoubleClick( gptr->secs, gptr->mics, imsg->Seconds, imsg->Micros ) )
  2429.     {
  2430.     run_game( gptr );
  2431.     gptr->secs = 0;
  2432.     gptr->mics = 0;
  2433.     return;
  2434.     }
  2435.  
  2436.     gptr->secs = imsg->Seconds;
  2437.     gptr->mics = imsg->Micros;
  2438. }
  2439.  
  2440. void setopt( gptr )
  2441.     register GPTR gptr;
  2442. {
  2443.     CopyOptions( curopts, gptr );
  2444.     if( EditOptions( curopts, gptr ) )
  2445.     SetOptions( curopts, gptr );
  2446. }
  2447.  
  2448. void menu_info()
  2449. {
  2450.     int itemno;
  2451.     register struct IntuiMessage *imsg;
  2452.     char *t;
  2453.     register GPTR gptr;
  2454.     register struct Gadget *gd;
  2455.     register struct FileInfoBlock *finfo;
  2456.     register struct Window *cwin;
  2457.     register int i;
  2458.     int done = 0;
  2459.     long lock, olock;
  2460.     char **sp;
  2461.     static int once = 0;
  2462.     long code, class, qual;
  2463.     static struct IntuiText itext[ 2 ];
  2464.     char commentstr[ 100 ], *s;
  2465.     int txtdiff = scrn->RastPort.TxHeight - 8;
  2466.  
  2467.     if( ( gptr = NeedGame() ) == NULL )
  2468.     return;
  2469.  
  2470.     if( ( lock = Lock( GameName( gptr, NULL ), ACCESS_READ ) ) == NULL )
  2471.     {
  2472.     /* Can't get lock, reload and return */
  2473.  
  2474.     errmsg( FLASH, "Can't Lock game save file: %s",
  2475.         GameName( gptr, NULL ) );
  2476.     MapGadgets( R_DISK, 1 );
  2477.     return;
  2478.     }
  2479.  
  2480.     finfo = (struct FileInfoBlock *)xmalloc(sizeof(struct FileInfoBlock));
  2481.     Examine( lock, finfo );
  2482.     UnLock( lock );
  2483.     strncpy( commentstr, finfo->fib_Comment, sizeof( finfo->fib_Comment ) );
  2484.     commentstr[ sizeof( finfo->fib_Comment ) ] = 0;
  2485.     free( finfo );
  2486.  
  2487.     for( i = 0; i < 2; ++i )
  2488.     {
  2489.     itext[ i ].FrontPen = C_BLACK;
  2490.     itext[ i ].BackPen = C_GREY;
  2491.     itext[ i ].DrawMode = JAM2;
  2492.     itext[ i ].TopEdge = 2;
  2493.     itext[ i ].LeftEdge = 4;
  2494.     }
  2495.     ReallocTools( gptr, 0 );
  2496.  
  2497.     if( !once )
  2498.     {
  2499.         Info_Comment.TopEdge += txtdiff*2;
  2500.     Info_NewWindowStructure6.Height += txtdiff * 7;
  2501.     for( gd = Info_NewWindowStructure6.FirstGadget;
  2502.         gd; gd = gd->NextGadget )
  2503.     {
  2504.         gd->TopEdge += txtdiff;
  2505.         if( gd->GadgetID != GADTOOLUP && gd->GadgetID != GADTOOLDOWN )
  2506.         gd->Height += txtdiff;
  2507.         switch( gd->GadgetID )
  2508.         {
  2509.         case 0:
  2510.             break;
  2511.  
  2512.         case GADEDITOPTS:
  2513.             gd->TopEdge += txtdiff*3;
  2514.             SetBorder( gd, -1 );
  2515.             break;
  2516.  
  2517.         case GADTOOLTYPES:
  2518.             gd->TopEdge += txtdiff*4;
  2519.             if( scrn->Height > 300 )
  2520.             gd->TopEdge += 2;
  2521.             SetBorder( gd, -1 );
  2522.             break;
  2523.  
  2524.         case GADDELTOOL:
  2525.             gd->TopEdge += txtdiff*3;
  2526.             SetBorder( gd, -1 );
  2527.             break;
  2528.  
  2529.         case GADADDTOOL:
  2530.             gd->TopEdge += txtdiff*3;
  2531.             SetBorder( gd, -1 );
  2532.             break;
  2533.  
  2534.         case GADSAVEINFO:
  2535.             gd->TopEdge += txtdiff*5;
  2536.             SetBorder( gd, -1 );
  2537.             break;
  2538.  
  2539.         case GADQUITINFO:
  2540.             gd->TopEdge += txtdiff*5;
  2541.             SetBorder( gd, -1 );
  2542.             break;
  2543.  
  2544.         case GADUSEINFO:
  2545.             gd->TopEdge += txtdiff*5;
  2546.             SetBorder( gd, -1 );
  2547.             break;
  2548.  
  2549.         case GADTOOLUP:
  2550.             gd->TopEdge += txtdiff*4;
  2551.             gd->Flags &= ~GADGHIGHBITS;
  2552.             gd->Flags |= GADGIMAGE|GADGHIMAGE;
  2553.             if( scrn->Height > 300 )
  2554.             {
  2555.             gd->GadgetRender = (APTR)&tall_up_selectimage;
  2556.             gd->SelectRender = (APTR)&tall_up_renderimage;
  2557.             gd->Height *= 2;
  2558.             if( txtdiff == 0 )
  2559.                 gd->TopEdge -= 2;
  2560.             }
  2561.             else
  2562.             {
  2563.             gd->GadgetRender = (APTR)&up_selectimage;
  2564.             gd->SelectRender = (APTR)&up_renderimage;
  2565.             }
  2566.             break;
  2567.  
  2568.         case GADTOOLDOWN:
  2569.             gd->TopEdge += txtdiff*5;
  2570.             gd->Flags &= ~GADGHIGHBITS;
  2571.             gd->Flags |= GADGIMAGE|GADGHIMAGE;
  2572.             if( scrn->Height > 300 )
  2573.             {
  2574.             gd->GadgetRender = (APTR)&tall_down_selectimage;
  2575.             gd->SelectRender = (APTR)&tall_down_renderimage;
  2576.             gd->Height *= 2;
  2577.             if( txtdiff == 0 )
  2578.                 gd->TopEdge += 4;
  2579.             }
  2580.             else
  2581.             {
  2582.             gd->GadgetRender = (APTR)&down_selectimage;
  2583.             gd->SelectRender = (APTR)&down_renderimage;
  2584.             }
  2585.             break;
  2586.  
  2587.         default:
  2588.             SetBorder( gd, -1 );
  2589.         }
  2590.     }
  2591.  
  2592.     ++once;
  2593.     }
  2594.  
  2595.     strncpy( Sbuff( &Info_Comment ), commentstr, 100 );
  2596.  
  2597.     /* The players name */
  2598.  
  2599.     strncpy( StrPlayer, ToolsEntry( gptr, "NAME" ), 100 );
  2600.     if( *StrPlayer == 0 )
  2601.     {
  2602.     strncpy( StrPlayer, gptr->name, 99 );
  2603.     }
  2604.  
  2605.     if( ( t = strrchr( StrPlayer, '.' ) ) && stricmp( t, ".sav" ) == 0 )
  2606.     {
  2607.     *t = 0;
  2608.     }
  2609.  
  2610.     /* The character class of the player */
  2611.  
  2612.     Info_Class.GadgetText = &itext[ 0 ];
  2613.     itext[ 0 ].IText = ToolsEntry( gptr, "CHARACTER" );
  2614.     if( *itext[ 0 ].IText == 0 )
  2615.     {
  2616.     itext[ 0 ].IText = players[ 0 ];
  2617.     SetToolLine( gptr, "CHARACTER", players[ 0 ] );
  2618.     }
  2619.  
  2620.     /* If there are ToolTypes entries, put the first one into the gadget */
  2621.  
  2622.     sp = gptr->dobj->do_ToolTypes;
  2623.     if( sp && *sp )
  2624.     strcpy( StrTools, *sp );
  2625.  
  2626.     if( IsEditEntry( StrTools, gptr ) )
  2627.     Info_ToolTypes.Flags &= ~GADGDISABLED;
  2628.     else
  2629.     Info_ToolTypes.Flags |= GADGDISABLED;
  2630.  
  2631.     Info_NewWindowStructure6.Screen = scrn;
  2632.     if( ( cwin = MyOpenWindow( &Info_NewWindowStructure6 ) ) == NULL )
  2633.     {
  2634.     errmsg( FLASH, "Can't create info window" );
  2635.     return;
  2636.     }
  2637.  
  2638.     itemno = 0;
  2639.     if( s = FindToolType( (char **) gptr->dobj->do_ToolTypes, "CHARACTER" ) )
  2640.     {
  2641.     s += 10;
  2642.     for( itemno = 0; players[ itemno ]; ++itemno )
  2643.     {
  2644.         if( strnicmp( s, players[ itemno ], strlen( s ) ) == 0 )
  2645.         break;
  2646.     }
  2647.     }
  2648.     if( !players[ itemno ] )
  2649.     itemno = 0;
  2650.  
  2651.     CheckOnly( &Info_MenuList6, 0, itemno );
  2652.     SetUpMenus( &Info_MenuList6, scrn );
  2653.     SetMenuStrip( cwin, &Info_MenuList6 );
  2654.  
  2655.     while( !done )
  2656.     {
  2657.     WaitPort( cwin->UserPort );
  2658.     while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
  2659.     {
  2660.         class = imsg->Class;
  2661.         code = imsg->Code;
  2662.         qual = imsg->Qualifier;
  2663.         gd = (struct Gadget *)imsg->IAddress;
  2664.  
  2665.         ReplyMsg( (struct Message *)imsg );
  2666.  
  2667.         switch( class )
  2668.         {
  2669.         case VANILLAKEY:
  2670.             if( code == '\33' || (code == 'b' && (qual&AMIGALEFT)) )
  2671.             {
  2672.             done = 1;
  2673.             }
  2674.             break;
  2675.  
  2676.         case CLOSEWINDOW:
  2677.             if( sp )
  2678.             {
  2679.             if( *sp )
  2680.                 free( *sp );
  2681.             *sp = strdup( StrTools );
  2682.             }
  2683.             done = 1;
  2684.             break;
  2685.  
  2686.         case GADGETUP:
  2687.             switch( gd->GadgetID )
  2688.             {
  2689.             case GADSAVEINFO:
  2690.             /* Write icon and quit. */
  2691.             SetToolLine( gptr, "NAME", StrPlayer );
  2692.             UpdateGameIcon( gptr );
  2693.             lock = Lock( gptr->dname, ACCESS_READ );
  2694.             if( lock )
  2695.             {
  2696.                 olock = CurrentDir( lock );
  2697.                 SetComment( gptr->fname, Sbuff( &Info_Comment ) );
  2698.                 CurrentDir( olock );
  2699.                 done = 1;
  2700.             }
  2701.             else
  2702.             {
  2703.                 errmsg( FLASH, "Can't access icon's directory" );
  2704.                 sp = gptr->dobj->do_ToolTypes;
  2705.                 strcpy( StrTools, *sp ? *sp : "" );
  2706.                 UpdateInfoWin( cwin );
  2707.             }
  2708.             break;
  2709.  
  2710.             case GADUSEINFO:
  2711.             /* Quit this loop. */
  2712.             done = 1;
  2713.             break;
  2714.  
  2715.             case GADQUITINFO:
  2716.             /* Reload icon and quit this loop. */
  2717.             RemoveGadget( win, &gptr->dobj->do_Gadget );
  2718.             RemoveGITEM( gptr );
  2719.             lastgaddown = NULL; /* very important... */
  2720.             MapGadgets( R_DISK, 1 );
  2721.             done = 1;
  2722.             break;
  2723.  
  2724.             case GADEDITOPTS:
  2725.             setopt( gptr );
  2726.             sp = gptr->dobj->do_ToolTypes;
  2727.             strcpy( StrTools, *sp ? *sp : "" );
  2728.             UpdateInfoWin( cwin );
  2729.             break;
  2730.  
  2731.             case GADADDTOOL:
  2732.             FreeTools( gptr );
  2733.             ReallocTools( gptr, 2 );
  2734.             sp = gptr->dobj->do_ToolTypes;
  2735.             for( i = 0; sp[ i ]; ++i )
  2736.                 ;
  2737.             sp[i] = strdup( "" );
  2738.             sp[i+1] = NULL;
  2739.             itext[ 0 ].IText =
  2740.                 ToolsEntry( gptr, "CHARACTER" );
  2741.             *StrTools = 0;
  2742.             Info_ToolTypes.Flags &= ~GADGDISABLED;
  2743.             UpdateInfoWin( cwin );
  2744.             sp += i;
  2745.             break;
  2746.  
  2747.             case GADDELTOOL:
  2748.             while( *sp = sp[1] )
  2749.                 ++sp;
  2750.             sp = gptr->dobj->do_ToolTypes;
  2751.             strcpy( StrTools, *sp ? *sp : "" );
  2752.             Info_ToolTypes.Flags &= ~GADGDISABLED;
  2753.             UpdateInfoWin( cwin );
  2754.             break;
  2755.  
  2756.             case GADTOOLTYPES:
  2757.             if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
  2758.             {
  2759.                 if( *sp )
  2760.                 free( *sp );
  2761.                 *sp = strdup( StrTools );
  2762.             }
  2763.             break;
  2764.  
  2765.             case GADTOOLDOWN:
  2766.             if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
  2767.             {
  2768.                 if( *sp )
  2769.                 free( *sp );
  2770.                 *sp = strdup( StrTools );
  2771.             }
  2772.  
  2773.             if( sp && sp[0] && sp[1] )
  2774.             {
  2775.                 ++sp;
  2776.                 strcpy( StrTools, *sp );
  2777.                 if( IsEditEntry( StrTools, gptr ) )
  2778.                 Info_ToolTypes.Flags &= ~GADGDISABLED;
  2779.                 else
  2780.                 Info_ToolTypes.Flags |= GADGDISABLED;
  2781.             }
  2782.             else
  2783.             {
  2784.                 if( sp && *sp )
  2785.                 strcpy( StrTools, *sp );
  2786.                 DisplayBeep( NULL );
  2787.             }
  2788.             break;
  2789.  
  2790.             case GADTOOLUP:
  2791.             if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
  2792.             {
  2793.                 if( *sp )
  2794.                 free( *sp );
  2795.                 *sp = strdup( StrTools );
  2796.             }
  2797.             if( sp && sp > gptr->dobj->do_ToolTypes )
  2798.             {
  2799.                 --sp;
  2800.                 if( *sp )
  2801.                 {
  2802.                 strcpy( StrTools, *sp );
  2803.                 if( IsEditEntry( StrTools, gptr ) )
  2804.                     Info_ToolTypes.Flags &= ~GADGDISABLED;
  2805.                 else
  2806.                     Info_ToolTypes.Flags |= GADGDISABLED;
  2807.                 }
  2808.             }
  2809.             else
  2810.             {
  2811.                 DisplayBeep( NULL );
  2812.             }
  2813.             break;
  2814.  
  2815.             case GADPLNAME:
  2816.             SetToolLine( gptr, "NAME", StrPlayer );
  2817.             sp = gptr->dobj->do_ToolTypes;
  2818.             strcpy( StrTools, *sp ? *sp : "" );
  2819.             UpdateInfoWin( cwin );
  2820.             break;
  2821.             }
  2822.             RefreshGList( &Info_ToolTypes, cwin, NULL, 1 );
  2823.             break;
  2824.  
  2825.             case MENUPICK:
  2826.                 while( code != MENUNULL )
  2827.                 {
  2828.             SetToolLine( gptr, "CHARACTER",
  2829.                     players[ ITEMNUM( code ) ] );
  2830.             itext[ 0 ].IText =
  2831.                     ToolsEntry( gptr, "CHARACTER" );
  2832.             sp = gptr->dobj->do_ToolTypes;
  2833.             strcpy( StrTools, *sp ? *sp : "" );
  2834.             UpdateInfoWin( cwin );
  2835.             code = ((struct MenuItem *)ItemAddress(
  2836.                 &Info_MenuList6, (long)code ))->NextSelect;
  2837.             }
  2838.             break;
  2839.         }
  2840.     }
  2841.     }
  2842.  
  2843.     SafeCloseWindow( cwin );
  2844. }
  2845.  
  2846. static void
  2847. UpdateInfoWin( cwin )
  2848.     struct Window *cwin;
  2849. {
  2850.     SetAPen( cwin->RPort, 0 );
  2851.     SetBPen( cwin->RPort, 0 );
  2852.     SetDrMd( cwin->RPort, JAM2 );
  2853.     RectFill( cwin->RPort,
  2854.     Info_Class.LeftEdge,
  2855.     Info_Class.TopEdge,
  2856.     Info_Class.LeftEdge + Info_Class.Width-1,
  2857.     Info_Class.TopEdge + Info_Class.Height-1 );
  2858.     RefreshGList( cwin->FirstGadget, cwin, NULL, -1 );
  2859. }
  2860.  
  2861. void
  2862. errmsg(int flash, char *str, ...)
  2863. {
  2864.     static char buf[ 200 ];
  2865.     int wid;
  2866.     va_list vp;
  2867.  
  2868.     va_start( vp, str );
  2869.  
  2870.     if( !win || !wbopen )
  2871.     {
  2872.     vprintf( str, vp );
  2873.     va_end( vp );
  2874.     return;
  2875.     }
  2876.     errup = 1;
  2877.     wid = ( win->Width + Message.LeftEdge - win->BorderRight - 3 ) /
  2878.             win->RPort->TxWidth;
  2879.     vsprintf( buf, str, vp );
  2880.     va_end( vp );
  2881.  
  2882.     SetAPen( win->RPort, 0 );
  2883.     SetBPen( win->RPort, 0 );
  2884.     SetDrMd( win->RPort, JAM2 );
  2885.     RectFill( win->RPort, Message.LeftEdge, Message.TopEdge,
  2886.     win->Width + Message.Width,
  2887.     Message.TopEdge + Message.Height - 1 );
  2888.  
  2889.     Message.GadgetText->IText = buf;
  2890.     RefreshGList( &Message, win, 0, 1 );
  2891.  
  2892.     if( flash == FLASH )
  2893.     DisplayBeep( scrn );
  2894. }
  2895.  
  2896. /*
  2897.  * Issue an error message to the users window because it can not be done
  2898.  * any other way.
  2899.  */
  2900.  
  2901. void error( str )
  2902.     register char *str;
  2903. {
  2904.     char s[ 50 ];
  2905.     if( scrn ) ScreenToBack( scrn );
  2906.     Delay( 10 );
  2907.     fprintf( stderr, "%s\n", str );
  2908.     fprintf( stderr, "Hit Return: " );
  2909.     fflush( stderr );
  2910.     gets( s );
  2911.     if( scrn ) ScreenToFront( scrn );
  2912. }
  2913.  
  2914. /*
  2915.  * Make the gadget deselected
  2916.  */
  2917.  
  2918. void SetGadgetUP( gad )
  2919.     register struct Gadget *gad;
  2920. {
  2921.     if( gad->Flags & GADGIMAGE )
  2922.     {
  2923.     DrawImage( win->RPort, (struct Image *)gad->GadgetRender,
  2924.         gad->LeftEdge, gad->TopEdge );
  2925.     }
  2926. #if 0
  2927.     RemoveGadget( win, gad );
  2928.     gad->Flags &= ~(SELECTED|GADGHIGHBITS);
  2929.     gad->Flags |= GADGHIMAGE|GADGIMAGE;
  2930.     gad->Activation |= TOGGLESELECT;
  2931.     AddGadget( win, gad, 0 );
  2932.     RefreshGList( gad, win, NULL, 1 );
  2933.     RemoveGadget( win, gad );
  2934.     gad->Flags &= ~(GADGHIGHBITS);
  2935.     gad->Flags |= GADGHNONE;
  2936.     gad->Activation &= ~TOGGLESELECT;
  2937.     AddGadget( win, gad, 0 );
  2938. #endif
  2939. }
  2940.  
  2941. /*
  2942.  * Make the gadget selected
  2943.  */
  2944.  
  2945. void SetGadgetDOWN( gad )
  2946.     register struct Gadget *gad;
  2947. {
  2948.     if( gad->Flags & GADGHIMAGE )
  2949.     {
  2950.     DrawImage( win->RPort, (struct Image *)gad->SelectRender,
  2951.         gad->LeftEdge, gad->TopEdge );
  2952.     }
  2953. #if 0
  2954.     RemoveGadget( win, gad );
  2955.     gad->Flags &= ~GADGHIGHBITS;
  2956.     gad->Flags |= GADGHIMAGE|GADGIMAGE|SELECTED;
  2957.     gad->Activation |= TOGGLESELECT;
  2958.     AddGadget( win, gad, 0 );
  2959.     RefreshGList( gad, win, NULL, 1 );
  2960.     RemoveGadget( win, gad );
  2961.     gad->Flags &= ~(GADGHIGHBITS);
  2962.     gad->Flags |= GADGHNONE;
  2963.     gad->Activation &= ~TOGGLESELECT;
  2964.     AddGadget( win, gad, 0 );
  2965. #endif
  2966. }
  2967.  
  2968. /*
  2969.  * Generate a requester for a string value.
  2970.  */
  2971.  
  2972. int StrRequest( prompt, buff, val )
  2973.     char *prompt, *buff, *val;
  2974. {
  2975.     struct Window *cwin;
  2976.     struct IntuiMessage *imsg;
  2977.     int done = 0, notcan = 1;
  2978.     long class, code, qual;
  2979.     struct Gadget *gd;
  2980.     static int once = 0;
  2981.     int txtdiff = scrn->RastPort.TxHeight - 8;
  2982.  
  2983.     *StrString = 0;
  2984.     if( val )
  2985.     strcpy( StrString, val );
  2986.     Str_NewWindowStructure5.Title = prompt;
  2987.  
  2988.     if( !once )
  2989.     {
  2990.     for( gd = Str_NewWindowStructure5.FirstGadget;
  2991.             gd; gd = gd->NextGadget )
  2992.     {
  2993.         if( gd->GadgetID != 0 )
  2994.         {
  2995.         gd->TopEdge += txtdiff;
  2996.         gd->Height += txtdiff;
  2997.         SetBorder( gd, -1 );
  2998.         }
  2999.     }
  3000.     ++once;
  3001.     Str_NewWindowStructure5.Height += txtdiff * 2;
  3002.     }
  3003.  
  3004.     Str_NewWindowStructure5.Screen = scrn;
  3005.     if( ( cwin = MyOpenWindow( &Str_NewWindowStructure5 ) ) == NULL )
  3006.     {
  3007.     errmsg( FLASH, "Can't create requester window" );
  3008.     return( 0 );
  3009.     }
  3010.  
  3011.     while( !done )
  3012.     {
  3013.     WaitPort( cwin->UserPort );
  3014.     while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
  3015.     {
  3016.         class = imsg->Class;
  3017.         code = imsg->Code;
  3018.         qual = imsg->Qualifier;
  3019.         gd = (struct Gadget *) imsg->IAddress;
  3020.         ReplyMsg( (struct Message *) imsg );
  3021.         switch( class )
  3022.         {
  3023.         case ACTIVEWINDOW:
  3024.             ActivateGadget( &Str_String, cwin, NULL );
  3025.             break;
  3026.  
  3027.         case GADGETUP:
  3028.             switch( gd->GadgetID )
  3029.             {
  3030.             case GADSTRCANCEL:
  3031.                 notcan = 0;
  3032.                 done = 1;
  3033.                 break;
  3034.  
  3035.             default:
  3036.                 strcpy( buff, StrString );
  3037.                 done = 1;
  3038.                 break;
  3039.             }
  3040.             break;
  3041.  
  3042.         case CLOSEWINDOW:
  3043.             strcpy( buff, StrString );
  3044.             done = 1;
  3045.             break;
  3046.  
  3047.         case VANILLAKEY:
  3048.             if( code == '\33' || code == 'b' && (qual&AMIGALEFT) )
  3049.             {
  3050.             done = 1;
  3051.             notcan = 0;
  3052.             }
  3053.             break;
  3054.         }
  3055.     }
  3056.     }
  3057.  
  3058.     SafeCloseWindow( cwin );
  3059.     return( notcan );
  3060. }
  3061.  
  3062. /*
  3063.  * Ask the user if they really want to do something.
  3064.  */
  3065.  
  3066. Ask( quest )
  3067.     char *quest;
  3068. {
  3069.     register struct Window *qwin;
  3070.     register struct Gadget *gd;
  3071.     register struct IntuiMessage *imsg;
  3072.     register int done = 0, quit = 1;
  3073.     int txtdiff;
  3074.     long class, code, qual;
  3075.     static int once = 0;
  3076.     static WORD areabuffer[ 80 ];
  3077.     static USHORT apat[] = { 0x5555, 0xaaaa };
  3078.     static struct AreaInfo areaInfo = { 0 };
  3079.     PLANEPTR pp;
  3080.     struct TmpRas tmpras;
  3081.  
  3082.     Quest_NewWindowStructure2.Screen = scrn;
  3083.     txtdiff = scrn->RastPort.TxHeight - 8;
  3084.     if( !once )
  3085.     {
  3086.     Quest_IntuiTextList2.TopEdge += txtdiff;
  3087.     Quest_Borders2.TopEdge += txtdiff;
  3088.     Quest_NewWindowStructure2.Height += txtdiff * 2;
  3089.     SetBorder( &Quest_Borders2, 3 );
  3090.     Quest_Yes.TopEdge += txtdiff;
  3091.     Quest_Yes.Height += txtdiff;
  3092.     SetBorder( &Quest_Yes, -1 );
  3093.     Quest_No.TopEdge += txtdiff;
  3094.     Quest_No.Height += txtdiff;
  3095.     SetBorder( &Quest_No, -1 );
  3096.     }
  3097.  
  3098.     memset( areabuffer, 0, sizeof( areabuffer ) );
  3099.     if( ( qwin = MyOpenWindow( &Quest_NewWindowStructure2 ) ) == NULL )
  3100.     {
  3101.     errmsg( FLASH, "Can't create requester window" );
  3102.     return( 1 );
  3103.     }
  3104.  
  3105.     pp = AllocRaster( qwin->Width, qwin->Height );
  3106.     if( pp )
  3107.     {
  3108.     InitArea( &areaInfo, areabuffer, 160/5 );
  3109.     qwin->RPort->AreaInfo = &areaInfo;
  3110.  
  3111.     InitTmpRas( &tmpras, pp, RASSIZE( qwin->Width, qwin->Height ) );
  3112.     qwin->RPort->TmpRas = &tmpras;
  3113.  
  3114.     SetAPen( qwin->RPort, C_WHITE );
  3115.     SetBPen( qwin->RPort, C_GREY );
  3116.     SetDrMd( qwin->RPort, JAM2 );
  3117.     SetAfPt( qwin->RPort, apat, 1 );
  3118.  
  3119.     AreaMove( qwin->RPort, qwin->BorderLeft, qwin->BorderTop );
  3120.     AreaDraw( qwin->RPort, qwin->Width-qwin->BorderRight, qwin->BorderTop );
  3121.     AreaDraw( qwin->RPort, qwin->Width - qwin->BorderRight,
  3122.         qwin->Height - qwin->BorderBottom );
  3123.     AreaDraw( qwin->RPort, qwin->BorderLeft,
  3124.         qwin->Height - qwin->BorderBottom );
  3125.     AreaDraw( qwin->RPort, qwin->BorderLeft, qwin->BorderTop );
  3126.     AreaEnd( qwin->RPort );
  3127.  
  3128.     SetAPen( qwin->RPort, C_GREY );
  3129.     SetBPen( qwin->RPort, C_GREY );
  3130.     SetDrMd( qwin->RPort, JAM2 );
  3131.     SetAfPt( qwin->RPort, NULL, 0 );
  3132.  
  3133.     RectFill( qwin->RPort,
  3134.         Quest_Borders2.LeftEdge,
  3135.         Quest_Borders2.TopEdge,
  3136.         Quest_Borders2.LeftEdge + Quest_Borders2.Width - 1,
  3137.         Quest_Borders2.TopEdge + Quest_Borders2.Height - 1 );
  3138.     RectFill( qwin->RPort,
  3139.         Quest_No.LeftEdge,
  3140.         Quest_No.TopEdge,
  3141.         Quest_No.LeftEdge + Quest_No.Width - 1,
  3142.         Quest_No.TopEdge + Quest_No.Height - 1 );
  3143.     RectFill( qwin->RPort,
  3144.         Quest_Yes.LeftEdge,
  3145.         Quest_Yes.TopEdge,
  3146.         Quest_Yes.LeftEdge + Quest_Yes.Width - 1,
  3147.         Quest_Yes.TopEdge + Quest_Yes.Height - 1 );
  3148.     RefreshGList( qwin->FirstGadget, qwin, NULL, -1 );
  3149.     }
  3150.  
  3151.     Quest_IntuiTextList2.LeftEdge = ( qwin->Width -
  3152.     ( qwin->RPort->TxWidth * strlen( quest ) ) ) / 2;
  3153.     Quest_IntuiTextList2.IText = quest;
  3154.     PrintIText( qwin->RPort, &Quest_IntuiTextList2, 0, 0 );
  3155.     while( !done )
  3156.     {
  3157.     WaitPort( qwin->UserPort );
  3158.     while( ( imsg = (void *) GetMsg( qwin->UserPort ) ) != NULL )
  3159.     {
  3160.         class = imsg->Class;
  3161.         code = imsg->Code;
  3162.         qual = imsg->Qualifier;
  3163.         gd = (struct Gadget *)imsg->IAddress;
  3164.  
  3165.         ReplyMsg( (struct Message *)imsg );
  3166.  
  3167.         switch( class )
  3168.         {
  3169.         case VANILLAKEY:
  3170.             if( imsg->Qualifier & AMIGALEFT )
  3171.             {
  3172.             switch( imsg->Code )
  3173.             {
  3174.                 case 'v': done = 1; quit = 0; break;
  3175.                 case '\33':
  3176.                 case 'b': done = 1; quit = 1; break;
  3177.             }
  3178.             }
  3179.             break;
  3180.  
  3181.         case CLOSEWINDOW:
  3182.             done = 1; quit = 1; break;
  3183.             break;
  3184.  
  3185.         case GADGETUP:
  3186.             switch( gd->GadgetID )
  3187.             {
  3188.             case GADQUESTYES: done = 1; quit = 0; break;
  3189.             case GADQUESTNO: done = 1; quit = 1; break;
  3190.             }
  3191.             break;
  3192.         }
  3193.     }
  3194.     }
  3195.  
  3196.     if( pp )
  3197.     FreeRaster( pp, qwin->Width, qwin->Height );
  3198.     once = 1;
  3199.     SafeCloseWindow( qwin );
  3200.     return( quit == 0 );
  3201. }
  3202.  
  3203. /* Make sure that a game icon is selected and return the pointer to
  3204.  * the GPTR structure associated with it.
  3205.  */
  3206.  
  3207. GPTR NeedGame()
  3208. {
  3209.     register GPTR gptr;
  3210.  
  3211.     if( lastgaddown == NULL )
  3212.     {
  3213.     errmsg( FLASH, "Must select a game" );
  3214.     return( NULL );
  3215.     }
  3216.  
  3217.     for( gptr = windowgads; gptr; gptr = gptr->nextwgad )
  3218.     {
  3219.     if( &gptr->dobj->do_Gadget == &lastgaddown->dobj->do_Gadget )
  3220.         break;
  3221.     }
  3222.  
  3223.     if( !gptr )
  3224.     {
  3225.     errmsg( FLASH, "BUG: invalid gadget selected for processing" );
  3226.     return( NULL );
  3227.     }
  3228.     return( gptr );
  3229. }
  3230.  
  3231. /* Set menu items SELECT flag based on 'enable' */
  3232.  
  3233. void ChgGameItems( menup, enable )
  3234.     struct Menu *menup;
  3235.     int enable;
  3236. {
  3237.     struct MenuItem *ip;
  3238.     int i;
  3239.     int ino;
  3240.  
  3241.     /* Make sure the 'Game' menu is there. */
  3242.  
  3243.     if( !menup || !(menup = menup->NextMenu) || !( ip = menup->FirstItem ) )
  3244.     {
  3245.     errmsg( FLASH, "BUG: invalid menu to disable with" );
  3246.     return;
  3247.     }
  3248.  
  3249.     /* Go through all items */
  3250.  
  3251.     for( i = 0; ip; ip = ip->NextItem, ++i )
  3252.     {
  3253.     switch( i )
  3254.     {
  3255.         case ITEM_INFO:
  3256.         case ITEM_COPYOPT:
  3257.         case ITEM_DISCARD:
  3258.         case ITEM_RENAME:
  3259.         ino = MENUITEMNO( 1,i,NOSUB );
  3260.         if( enable )
  3261.             OnMenu( win, ino );
  3262.         else
  3263.             OffMenu( win, ino );
  3264.         break;
  3265.     }
  3266.     }
  3267. }
  3268.  
  3269. /* Set menu items SELECT flag based on 'enable' for NEWGAME gadget */
  3270.  
  3271. void ChgNewGameItems( menup, enable )
  3272.     struct Menu *menup;
  3273.     int enable;
  3274. {
  3275.     struct MenuItem *ip;
  3276.     int i;
  3277.     int ino;
  3278.  
  3279.     /* Make sure the 'Game' menu is there. */
  3280.  
  3281.     if( !menup || !(menup = menup->NextMenu) || !( ip = menup->FirstItem ) )
  3282.     {
  3283.     errmsg( FLASH, "BUG: invalid menu to disable with" );
  3284.     return;
  3285.     }
  3286.  
  3287.     /* Go through all items */
  3288.  
  3289.     for( i = 0; ip; ip = ip->NextItem, ++i )
  3290.     {
  3291.     switch( i )
  3292.     {
  3293.         case ITEM_RENAME:
  3294.         case ITEM_DISCARD:
  3295.         ino = MENUITEMNO( 1,i,NOSUB );
  3296.         OffMenu( win, ino );
  3297.         break;
  3298.  
  3299.         case ITEM_COPYOPT:
  3300.         case ITEM_INFO:
  3301.         ino = MENUITEMNO( 1,i,NOSUB );
  3302.         if( enable )
  3303.             OnMenu( win, ino );
  3304.         else
  3305.             OffMenu( win, ino );
  3306.         break;
  3307.     }
  3308.     }
  3309. }
  3310.  
  3311. /* Edit the OPTIONS= line with a window.  The optr[] array is set up
  3312.  * for the editing already, and will be returned with the values
  3313.  * of the members changed based on the users input
  3314.  */
  3315.  
  3316. int EditOptions( optr, gptr )
  3317.     OPTR optr;
  3318.     GPTR gptr;
  3319. {
  3320.     int done = 0, quit = 0;
  3321.     register struct Window *cwin;
  3322.     register struct IntuiMessage *imsg;
  3323.     register struct Gadget *gd;
  3324.     long code, class, qual;
  3325.     struct IntuiText *ip;
  3326.     static int once = 0;
  3327.     int i;
  3328.     int txtdiff = scrn->RastPort.TxHeight - 8;
  3329.  
  3330.     if( !once )
  3331.     {
  3332.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOLITCORRIDOR ))
  3333.     {
  3334.         struct Gadget *g;
  3335.         for( g = Options_NewWindowStructure3.FirstGadget;
  3336.                 g; g = g->NextGadget )
  3337.         {
  3338.         if( g == gd )
  3339.             continue;
  3340.         if( g->TopEdge == gd->TopEdge )
  3341.         {
  3342.             g->Height += txtdiff;
  3343.         }
  3344.         }
  3345.         gd->Height += txtdiff;
  3346.     }
  3347.  
  3348.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOTIME ))
  3349.     {
  3350.         struct Gadget *g;
  3351.         for( g = Options_NewWindowStructure3.FirstGadget;
  3352.                 g; g = g->NextGadget )
  3353.         {
  3354.         if( g == gd )
  3355.             continue;
  3356.         if( g->TopEdge == gd->TopEdge )
  3357.         {
  3358.             g->TopEdge += txtdiff;
  3359.             g->Height += txtdiff;
  3360.         }
  3361.         }
  3362.         gd->TopEdge += txtdiff;
  3363.         gd->Height += txtdiff;
  3364.     }
  3365.  
  3366.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOPICKUP ))
  3367.     {
  3368.         struct Gadget *g;
  3369.         for( g = Options_NewWindowStructure3.FirstGadget; g; g = g->NextGadget )
  3370.         {
  3371.         if( g == gd )
  3372.             continue;
  3373.         if( g->TopEdge == gd->TopEdge )
  3374.         {
  3375.             g->TopEdge += txtdiff*2;
  3376.             g->Height += txtdiff;
  3377.         }
  3378.         }
  3379.         gd->TopEdge += txtdiff*2;
  3380.         gd->Height += txtdiff;
  3381.     }
  3382.  
  3383.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOHILITEPET ))
  3384.     {
  3385.         struct Gadget *g;
  3386.         for( g = Options_NewWindowStructure3.FirstGadget; g; g = g->NextGadget )
  3387.         {
  3388.         if( g == gd )
  3389.             continue;
  3390.         if( g->TopEdge == gd->TopEdge )
  3391.         {
  3392.             g->TopEdge += txtdiff*3;
  3393.             g->Height += txtdiff;
  3394.         }
  3395.         }
  3396.         gd->TopEdge += txtdiff*3;
  3397.         gd->Height += txtdiff;
  3398.     }
  3399.  
  3400.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOPACKORDER ))
  3401.     {
  3402.         gd->TopEdge += txtdiff*4;
  3403.         gd->Height += txtdiff;
  3404.     }
  3405.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOPICKUPTYPES ))
  3406.     {
  3407.         gd->TopEdge += txtdiff*4;
  3408.         gd->Height += txtdiff;
  3409.     }
  3410.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOCATNAME ))
  3411.     {
  3412.         gd->TopEdge += txtdiff*5;
  3413.         gd->Height += txtdiff;
  3414.     }
  3415.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOWINDOWTYPE ))
  3416.     {
  3417.         gd->TopEdge += txtdiff*5;
  3418.         gd->Height += txtdiff;
  3419.     }
  3420.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADODOGNAME ))
  3421.     {
  3422.         gd->TopEdge += txtdiff*6;
  3423.         gd->Height += txtdiff;
  3424.     }
  3425.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOMSGHISTORY ))
  3426.     {
  3427.         gd->TopEdge += txtdiff*6;
  3428.         gd->Height += txtdiff;
  3429.     }
  3430.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOFRUIT ))
  3431.     {
  3432.         gd->TopEdge += txtdiff*7;
  3433.         gd->Height += txtdiff;
  3434.     }
  3435.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOPALETTE ))
  3436.     {
  3437.         gd->TopEdge += txtdiff*7;
  3438.         gd->Height += txtdiff;
  3439.     }
  3440.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOOBJECTS ))
  3441.     {
  3442.         gd->TopEdge += txtdiff*8;
  3443.         gd->Height += txtdiff;
  3444.     }
  3445.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOSCORE ))
  3446.     {
  3447.         gd->TopEdge += txtdiff*8;
  3448.         gd->Height += txtdiff;
  3449.     }
  3450.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADONAME ))
  3451.     {
  3452.         gd->TopEdge += txtdiff*9;
  3453.         gd->Height += txtdiff;
  3454.     }
  3455.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOPETTYPE ))
  3456.     {
  3457.         gd->TopEdge += txtdiff*9;
  3458.         gd->Height += txtdiff;
  3459.     }
  3460.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOOKAY ))
  3461.     {
  3462.         gd->TopEdge += txtdiff*10;
  3463.         gd->Height += txtdiff;
  3464.     }
  3465.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, GADOCANCEL ))
  3466.     {
  3467.         gd->TopEdge += txtdiff*10;
  3468.         gd->Height += txtdiff;
  3469.     }
  3470.     Options_NewWindowStructure3.Height += txtdiff*12;
  3471.     Options_NewWindowStructure3.TopEdge -= txtdiff*12;
  3472.     if( Options_NewWindowStructure3.Height +
  3473.         Options_NewWindowStructure3.TopEdge >= scrn->Height )
  3474.     {
  3475.         Options_NewWindowStructure3.TopEdge = scrn->Height -
  3476.         Options_NewWindowStructure3.Height - 1;
  3477.     }
  3478.     if( Options_NewWindowStructure3.TopEdge < 0 )
  3479.         Options_NewWindowStructure3.TopEdge = 0;
  3480.     if( Options_NewWindowStructure3.Height > scrn->Height )
  3481.         Options_NewWindowStructure3.Height = scrn->Height;
  3482.  
  3483.     /* Now that heights are correct, render borders */
  3484.     for( gd = Options_NewWindowStructure3.FirstGadget;
  3485.         gd; gd = gd->NextGadget )
  3486.     {
  3487.         if( gd->GadgetID != 0 )
  3488.         {
  3489.         gd->TopEdge += txtdiff;
  3490.         SetBorder( gd, -1 );
  3491.         }
  3492.     }
  3493.  
  3494.     for( ip = &Options_IntuiTextList3; ip; ip = ip->NextText )
  3495.     {
  3496.         /* Pack Order:  and  Pickup: */
  3497.         if( ( *ip->IText == 'P' && ip->IText[2] == 'c' ) )
  3498.         {
  3499.         ip->TopEdge += txtdiff * 4;
  3500.         }
  3501.         /* Cat Name:  and  Window Type: */
  3502.         else if( ( *ip->IText == 'C' ) ||
  3503.             ( *ip->IText == 'W' ) )
  3504.         {
  3505.         ip->TopEdge += txtdiff * 5;
  3506.         }
  3507.         /* Dog Name:  and  Msg History: */
  3508.         else if( ( *ip->IText == 'D' ) ||
  3509.             ( *ip->IText == 'M' ) )
  3510.         {
  3511.         ip->TopEdge += txtdiff * 6;
  3512.         }
  3513.         /* Fruit:  and  Pallete: */
  3514.         else if( ( *ip->IText == 'F' ) ||
  3515.             ( *ip->IText == 'P' && ip->IText[2] == 'l' ) )
  3516.         {
  3517.         ip->TopEdge += txtdiff * 7;
  3518.         }
  3519.         /* Objects:  and  Score: */
  3520.         else if( ( *ip->IText == 'O' ) ||
  3521.                 ( *ip->IText == 'S' ) )
  3522.         {
  3523.         ip->TopEdge += txtdiff * 8;
  3524.         }
  3525.         /* Name:  and  Pet Type: */
  3526.         else if(( *ip->IText == 'N' ) ||
  3527.             ( *ip->IText == 'P' && ip->IText[1] == 'e' ) )
  3528.         {
  3529.         ip->TopEdge += txtdiff * 9;
  3530.         }
  3531.     }
  3532.     once = 1;
  3533.     }
  3534.  
  3535.     /* Set Gadgets based on options settings */
  3536.  
  3537.     for( i = 0; optr[ i ].name; ++i )
  3538.     {
  3539.     if( gd = FindGadget( NULL, &Options_NewWindowStructure3, optr[i].id ))
  3540.     {
  3541.         /* If string valued option, set string */
  3542.         if( optr[ i ].optstr )
  3543.         {
  3544.             char *t;
  3545.  
  3546.         if( optr[ i ].id == GADOPALETTE &&
  3547.                     ( optr[i].optstr == NULL || *optr[i].optstr == 0 ) )
  3548.         {
  3549.             if( gptr && ( t = ToolsEntry( gptr, "PENS" ) ) )
  3550.             {
  3551.             strcpy( Sbuff( gd ), t );
  3552.             }
  3553.             else
  3554.             {
  3555.             strcpy( Sbuff( gd ), options[ PENS_IDX ] );
  3556.             }
  3557.             for( t = strchr( Sbuff( gd ), ',' ); t; t = strchr( t, ',' ) )
  3558.                 *t = '/';
  3559.         }
  3560.         else
  3561.             strcpy( Sbuff( gd ), optr[i].optstr );
  3562.         }
  3563.         else
  3564.         {
  3565.         /* If binary option, set the gadget state */
  3566.         if( optr[i].optval )
  3567.             gd->Flags |= SELECTED;
  3568.         else
  3569.             gd->Flags &= ~SELECTED;
  3570.         }
  3571.     }
  3572.     else
  3573.     {
  3574.         errmsg( FLASH, "Can't find gadget %d in options window",
  3575.                                 optr[i].id);
  3576.     }
  3577.     }
  3578.  
  3579.     Options_NewWindowStructure3.Screen = scrn;
  3580.     if( ( cwin = MyOpenWindow( &Options_NewWindowStructure3 ) ) == NULL )
  3581.     {
  3582.     errmsg( FLASH, "Can't create requester window" );
  3583.     return(0);
  3584.     }
  3585.     PrintIText( cwin->RPort, &Options_IntuiTextList3, 0, txtdiff );
  3586.  
  3587.     while( !done )
  3588.     {
  3589.     WaitPort( cwin->UserPort );
  3590.     while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
  3591.     {
  3592.         class = imsg->Class;
  3593.         code = imsg->Code;
  3594.         qual = imsg->Qualifier;
  3595.         gd = (struct Gadget *)imsg->IAddress;
  3596.         ReplyMsg( (struct Message *) imsg );
  3597.         switch( class )
  3598.         {
  3599.         case ACTIVEWINDOW:
  3600.             ActivateGadget(
  3601.             FindGadget( cwin, 0, GADOPACKORDER ), cwin, 0 );
  3602.             break;
  3603.  
  3604.         case VANILLAKEY:
  3605.             if( code == '\33' )
  3606.             {
  3607.             done = 1;
  3608.             quit = 1;
  3609.             }
  3610.             else if( code == 'v' && (qual & AMIGALEFT) )
  3611.             done = 1;
  3612.             else if( code == 'b' && (qual & AMIGALEFT) )
  3613.             {
  3614.             done = 1;
  3615.             quit = 1;
  3616.             }
  3617.             break;
  3618.  
  3619.         case CLOSEWINDOW:
  3620.             done = 1;
  3621.             break;
  3622.  
  3623.         case GADGETUP:
  3624.             switch( gd->GadgetID )
  3625.             {
  3626.             case GADOPACKORDER:
  3627.                 ActivateGadget(
  3628.                 FindGadget( cwin, 0, GADOPICKUPTYPES ),
  3629.                 cwin, 0 );
  3630.                 break;
  3631.  
  3632.             case GADOCATNAME:
  3633.                 ActivateGadget(
  3634.                 FindGadget( cwin, 0, GADOWINDOWTYPE ),
  3635.                 cwin, 0 );
  3636.                 break;
  3637.  
  3638.             case GADODOGNAME:
  3639.                 ActivateGadget(
  3640.                 FindGadget( cwin, 0, GADOMSGHISTORY ),
  3641.                 cwin, 0 );
  3642.                 break;
  3643.  
  3644.             case GADOFRUIT:
  3645.                 ActivateGadget(
  3646.                 FindGadget( cwin, 0, GADOPALETTE ),
  3647.                 cwin, 0 );
  3648.                 break;
  3649.  
  3650.             case GADOOBJECTS:
  3651.                 ActivateGadget(
  3652.                 FindGadget( cwin, 0, GADOSCORE ),
  3653.                 cwin, 0 );
  3654.                 break;
  3655.  
  3656.             case GADONAME:
  3657.                 ActivateGadget(
  3658.                 FindGadget( cwin, 0, GADOPETTYPE ),
  3659.                 cwin, 0 );
  3660.                 break;
  3661.  
  3662.             case GADOPICKUPTYPES:
  3663.                 ActivateGadget(
  3664.                 FindGadget( cwin, 0, GADOCATNAME ),
  3665.                 cwin, 0 );
  3666.                 break;
  3667.  
  3668.             case GADOWINDOWTYPE:
  3669.                 ActivateGadget(
  3670.                 FindGadget( cwin, 0, GADODOGNAME ),
  3671.                 cwin, 0 );
  3672.                 break;
  3673.  
  3674.             case GADOMSGHISTORY:
  3675.                 ActivateGadget(
  3676.                 FindGadget( cwin, 0, GADOFRUIT ),
  3677.                 cwin, 0 );
  3678.                 break;
  3679.  
  3680.             case GADOPALETTE:
  3681.                 ActivateGadget(
  3682.                 FindGadget( cwin, 0, GADOOBJECTS ),
  3683.                 cwin, 0 );
  3684.                 break;
  3685.  
  3686.             case GADOSCORE:
  3687.                 ActivateGadget(
  3688.                 FindGadget( cwin, 0, GADONAME ),
  3689.                 cwin, 0 );
  3690.                 break;
  3691.  
  3692.             case GADOPETTYPE:
  3693.                 break;
  3694.  
  3695.             case GADOOKAY:
  3696.                 done = 1;
  3697.                 break;
  3698.  
  3699.             case GADOCANCEL:
  3700.                 quit = 1;
  3701.                 done = 1;
  3702.                 break;
  3703.  
  3704.             default:
  3705.                 for( i = 0; optr[i].name; ++i )
  3706.                 {
  3707.                 if( optr[i].id == gd->GadgetID )
  3708.                     break;
  3709.                 }
  3710.  
  3711.                 if( optr[i].name )
  3712.                 {
  3713.                 if( optr[ i ].optstr != NULL )
  3714.                 {
  3715.                     if( *optr[i].optstr )
  3716.                     free( optr[i].optstr );
  3717.  
  3718.                     if( *Sbuff(gd) == 0 )
  3719.                     {
  3720.                     optr[i].optstr = "";
  3721.                     }
  3722.                     else
  3723.                     {
  3724.                     optr[i].optstr = strdup(Sbuff(gd));
  3725.                     }
  3726.                 }
  3727.                 else
  3728.                 {
  3729.                     optr[i].optval =
  3730.                         ( gd->Flags & SELECTED ) != 0;
  3731.                 }
  3732.                 }
  3733.                 break;
  3734.             }
  3735.             break;
  3736.         }
  3737.     }
  3738.     }
  3739.  
  3740.     SafeCloseWindow( cwin );
  3741.     return( quit == 0 );
  3742. }
  3743.  
  3744. /*
  3745.  * Put options structure into a string and then make that the
  3746.  * options[ OPTIONS_IDX ] value
  3747.  */
  3748.  
  3749. void PutOptions( optr )
  3750.     register OPTR optr;
  3751. {
  3752.     register struct Gadget *gd;
  3753.     register int i, olen = 4096, rlen, didone;
  3754.     register char *optbuf;
  3755.  
  3756.     while( olen > 256 )
  3757.     {
  3758.     if( ( optbuf = xmalloc( olen ) ) != NULL )
  3759.     {
  3760.         break;
  3761.     }
  3762.     olen /= 2;
  3763.     }
  3764.  
  3765.     if( optbuf == NULL )
  3766.     {
  3767.     errmsg( FLASH, "No memory left for options buffer" );
  3768.     return;
  3769.     }
  3770.  
  3771.     /* Account for nul terminator */
  3772.     *optbuf = 0;
  3773.  
  3774.     for( i = 0; optr[i].name; ++i )
  3775.     {
  3776.     --olen;
  3777.     didone = 0;
  3778.     rlen = 0;
  3779.     gd = FindGadget( 0, &Options_NewWindowStructure3, optr[i].id );
  3780.  
  3781.     /* If name:value option */
  3782.     if( optr[i].optstr != NULL )
  3783.     {
  3784.         /* If gadget contains some text */
  3785.         if( gd && *Sbuff( gd ) )
  3786.         {
  3787.         /* Free a previously allocated string */
  3788.         if( optr[i].optstr && *optr[i].optstr )
  3789.             free( optr[i].optstr );
  3790.  
  3791.         /* Store "" or save string away */
  3792.         if( *Sbuff(gd) == 0 )
  3793.             optr[i].optstr = "";
  3794.         else
  3795.             optr[i].optstr = strdup(Sbuff(gd));
  3796.  
  3797.         rlen = strlen( optr[i].optstr ) + strlen( optr[i].name ) + 1;
  3798.         if( rlen <= olen )
  3799.         {
  3800.             sprintf( optbuf + strlen(optbuf), "%s:%s",
  3801.             optr[i].name, optr[i].optstr );
  3802.         }
  3803.         didone = 1;
  3804.         }
  3805.     }
  3806.     else
  3807.     {
  3808.         if( optr[i].optval != optr[i].defval )
  3809.         {
  3810.         if( olen >= (rlen = strlen( optr[i].name ) +
  3811.             (optr[i].optval == 0 ) ) )
  3812.         {
  3813.             if( optr[i].optval == 0 )
  3814.             strcat( optbuf, "!" );
  3815.             strcat( optbuf, optr[i].name );
  3816.         }
  3817.         didone = 1;
  3818.         }
  3819.     }
  3820.  
  3821.     if( rlen > olen )
  3822.     {
  3823.         errmsg( FLASH, "Out of space for options" );
  3824.         break;
  3825.     }
  3826.     if( didone )
  3827.         strcat( optbuf, "," );
  3828.     }
  3829.  
  3830.     /* Remove trailing ',' */
  3831.  
  3832.     if( *optbuf )
  3833.     optbuf[ strlen( optbuf ) - 1 ] = 0;
  3834.  
  3835.     setoneopt( OPTIONS_IDX, optbuf );
  3836.     free( optbuf );
  3837. }
  3838.  
  3839. char *basename( str )
  3840.     char *str;
  3841. {
  3842.     char *t;
  3843.  
  3844.     t = strrchr( str, '/' );
  3845.     if( !t )
  3846.     t = strrchr( str, ':' );
  3847.     if( !t )
  3848.     t = str;
  3849.     else
  3850.     ++t;
  3851.     return( t );
  3852. }
  3853.